Compare commits

...

56 Commits

Author SHA1 Message Date
ZhanGSKen e8e7887926 <stallhelper>APK 15.20.5 release Publish. 2026-05-22 19:00:55 +08:00
aBuild 4acae6726c 列表项排档时间旁增加倒计时/已过时间显示
- 排档时间行改为横向布局,新增蓝色 TextView
- 排档时间大于当前时间显示剩余X月X天X小时
- 排档时间小于等于当前时间显示已过X月X天X小时
2026-05-22 18:58:54 +08:00
ZhanGSKen e61c36dfed <stallhelper>APK 15.20.4 release Publish. 2026-05-22 17:22:44 +08:00
aBuild 297d840bff 排档按钮增加确认对话框,列表项背景色标识已过期任务
- 点击 ▷ 按钮弹出确认对话框,显示任务详情与排档后时间
- 确认后执行排档,取消则不做任何操作
- 排档时间不超过当前时间的列表项背景色设为浅绿色
- 新增 dialog_schedule_confirm.xml 布局文件
- 新增 colorScheduleFutureBackground 颜色资源
2026-05-22 17:16:29 +08:00
aBuild 43e783f5aa 任务列表新增正序排列功能,编辑对话框添加现在按钮
- 添加 sortTaskList() 按排档时间正序排列列表
- 加载、添加、编辑、删除、排档后均排序并刷新界面
- 编辑/添加对话框的排档时间输入框旁增加现在按钮
- 点击现在按钮将当前整点时间填入输入框
2026-05-22 17:01:34 +08:00
aBuild a11bad310b 修复任务排档performSchedule逻辑:排档时间应更新当前任务而非下一任务
- performSchedule 改为将新时间设置给当前任务自身
- 添加 notifyItemChanged(position) 刷新当前列表项
- 补充 saveTaskData() 持久化数据
2026-05-22 16:48:09 +08:00
ZhanGSKen 0ad264c4aa <stallhelper>APK 15.20.3 release Publish. 2026-05-21 00:15:15 +08:00
Transformers 81c2b781b6 优化任务排档功能:添加数据持久化、增删功能及界面优化
- 取消测试数据,使用TaskSchedulerBean的存储方法实现数据持久化
- 添加loadTaskData()和saveTaskData()方法,实现数据加载和保存
- 添加showAddTaskDialog()方法,支持通过悬浮按钮添加新任务
- 添加showDeleteConfirmDialog()方法,支持长按删除并二次确认
- 修复删除对话框中的FrameLayout强制转换异常
- 在添加/编辑任务后自动保存数据
- 布局文件添加悬浮添加按钮,背景使用深色colorPrimaryDark
- 调整根布局为FrameLayout以支持悬浮按钮
2026-05-21 00:12:32 +08:00
Transformers de63acc114 修复TaskSchedulerActivity编译错误:使用PopupMenu替代抽象类ContextMenu
- 添加PopupMenu导入
- 替换直接实例化ContextMenu的代码
- 保持原有菜单功能逻辑不变
2026-05-18 20:18:20 +08:00
ZhanGSKen 02c27c37f7 TaskSchedulerActivity类改用内嵌函数创建内容菜单。 2026-05-18 20:12:06 +08:00
ZhanGSKen 774ecca1b2 <stallhelper>APK 15.20.2 release Publish. 2026-05-18 19:22:43 +08:00
Transformers 3af96c7f12 优化App.java初始化流程
- 添加cc.winboll.studio.libappbase.BuildConfig导入
- 移除onCreate()中重复的super.onCreate()调用
- 优化调试模式设置逻辑,先检查当前调试状态后再设置
- 保持build.properties版本号自动更新
2026-05-18 19:13:22 +08:00
ZhanGSKen 2e30b8667d 更换排档任务操作方式,未调试。。。 2026-05-18 17:02:35 +08:00
ZhanGSKen 96fca63627 优化排档任务列表视图 2026-05-18 13:41:25 +08:00
Transformers f9d6198897 feat: 修改任务排档时间为时间戳格式,支持年月日显示
主要修改:
1. TaskSchedulerBean数据模型:
   - 将currentScheduleTime字段类型从String改为long(时间戳格式)
   - 更新构造函数参数类型
   - 更新getter/setter方法
   - 更新JSON序列化/反序列化,使用nextLong()和value(long)

2. TaskSchedulerActivity逻辑:
   - 添加formatTimestamp()方法,将时间戳格式化为"yyyy-MM-dd HH"
   - 添加parseTimeString()方法,解析时间字符串为时间戳
   - 添加convertToTotalMinutes()方法,将月、天、小时转换为总分钟数
   - 添加formatDurationToString()方法,格式化排档幅度显示
   - 更新initSampleData(),使用Calendar生成时间戳示例数据
   - 更新performSchedule(),直接使用时间戳计算,更准确可靠
   - 更新对话框显示和保存逻辑,支持时间戳的显示和输入
   - 更新ViewHolder变量名和显示逻辑

3. 布局文件:
   - dialog_task_edit.xml:
     - 修改时间输入提示为"当前排档时间(yyyy-MM-dd HH):"
     - 将排档幅度从单输入框改为月、天、小时三个输入框
   - item_task_scheduler.xml:
     - 修改标签从"时间:"改为"排档时间:"
     - 简化布局结构,删除冗余部分

4. 命名更新:
   - 所有相关变量和方法名从startTime改为currentScheduleTime
   - 提示文字相应更新
2026-05-18 13:31:51 +08:00
Transformers 3609c07daf feat: 完善任务排档功能 - 添加数据模型、列表显示和编辑对话框
新增功能:
- 创建 TaskSchedulerBean 数据模型,支持任务名称、备注、起始时间、排档幅度
- 添加任务项布局 item_task_scheduler.xml,包含排档按钮
- 创建编辑对话框布局 dialog_task_edit.xml,支持编辑所有字段
- 实现 RecyclerView 列表显示任务数据
- 添加 showEditTaskDialog() 编辑对话框功能
- 实现 performSchedule() 排档时间计算功能
- 添加 addMinutesToTime() 时间计算工具方法
- 完整的输入验证逻辑
- 示例数据初始化

修改内容:
- 更新 activity_task_scheduler.xml 为 RecyclerView 布局
- 修改 TaskSchedulerActivity 继承 WinBoLLActivity
- 实现完整的列表适配器和 ViewHolder
- 添加排档按钮点击事件处理
2026-05-18 03:22:11 +08:00
Transformers 510f50458b feat: 添加任务排档功能
- 新增 TaskSchedulerActivity 任务排档页面
- 新增 ic_task_scheduler 任务排档专用图标
- 新增 activity_task_scheduler 任务排档布局文件
- 在主界面添加任务排档入口按钮
- 在 AndroidManifest.xml 中注册新 Activity
- 在 MainActivity 中添加跳转逻辑
2026-05-18 02:56:14 +08:00
ZhanGSKen 9806ed668d 编译测试 2026-05-18 02:25:30 +08:00
ZhanGSKen 11d5cf39aa 移除冗余项目 2026-05-18 02:23:19 +08:00
ZhanGSKen b0f8a25055 Merge branch 'projects_keeper_tag' into stallhelper 2026-05-18 02:21:49 +08:00
ZhanGSKen 3359270103 更新基础类库 2026-05-18 02:19:14 +08:00
ZhanGSKen 893cf504c2 添加“./StallHelper_Bck20260515_150311_246/stallhelper/”源码 2026-05-18 02:15:02 +08:00
ZhanGSKen ae5d9b6854 建立个人使用的应用项目 2026-05-17 23:24:33 +08:00
qinglong 193011a80d 合并模块AES 同步最新时间标签aes-v15.20.4 2026-05-17 21:00:01 +08:00
ZhanGSKen 0b5eea447b 更新基础类 2026-05-17 16:23:52 +08:00
ZhanGSKen 6dbcca8fad Merge branch 'projects_keeper_tag' into winboll 2026-05-17 16:22:53 +08:00
qinglong eb3d8f4806 合并模块APPBase 同步最新时间标签appbase-v15.20.15 2026-05-17 16:20:01 +08:00
ZhanGSKen aa1b701c8b 合并模块APPBase 同步最新时间标签appbase-v15.20.14 2026-05-17 15:55:39 +08:00
ZhanGSKen fc20bd56b4 合并模块APPBase 同步最新时间标签appbase-v15.20.13 2026-05-17 15:52:14 +08:00
ZhanGSKen e92538850f 合并模块APPBase 同步最新时间标签appbase-v15.20.12 2026-05-17 15:46:18 +08:00
ZhanGSKen 81b7af0ec4 1. 排序规则彻底换掉
不再按版本号排序,按标签创建时间从新到旧,永远拿到最后发布的最新标签
​
2. 增加  -f  强制覆盖,确保拉取最新文件
​
3. 你现在  appbase-v15.20.12  是后打的标签,脚本会直接优先抓取它
​
4. 无差异也会正常同步最新标签版本文件
2026-05-17 15:45:57 +08:00
ZhanGSKen e2b4bddb61 BugFix 2026-05-17 15:43:18 +08:00
ZhanGSKen cbca61ad84 1. 删掉手动拼接标签逻辑,直接取用远程完整标签名,杜绝  appbase- 空格版本
​
2. 使用  git rev-parse --verify 标签^{commit}  精准拿远程标签commit
​
3. 合并来源强制指定  origin/模块名  远程分支
​
4. 空标签直接跳过,不再出现  xxx-  非法标签
​
5. 检出语法标准: git checkout 远程分支 commit -- 目录
2026-05-17 15:37:37 +08:00
ZhanGSKen 28bc3a86e3 1. 版本排序彻底修复
按  大版本.中版本.小版本.迭代号  分段数字排序,优先抓取  appbase-v15.20.12  而不是旧版
​
2. 检出命令修正
统一使用  git checkout 提交哈希 -- 目录  语法,不再报路径不存在
2026-05-17 15:34:14 +08:00
ZhanGSKen 79f7f682b3 合并模块APPBase 来源最新标签:appbase-v15.20.11 提交点:c7184ad6df0092106e535308ba486a9503395042 2026-05-17 15:25:41 +08:00
ZhanGSKen 8fa09a9f99 demoapp、winboll、aes  没有  xxx-版本号  格式标签,跳过属于正常
​
2.  appbase  成功抓到标签和commit,只是命令语法错导致拉取失败,改完即可正常合并
2026-05-17 15:25:10 +08:00
ZhanGSKen 555c5deef9 1.  get_module_latest_tag  → 抓取远程该模块最新Tag
​
2.  get_commit_by_tag  → 用最新Tag查出唯一对应提交Commit
​
3. 校验Tag/Commit非空
​
4. 执行合并命令git checkout origin/模块名  commit哈希:模块文件夹
 
 
 
5. 仅添加对应目录,生成带标签+commit的提交日志
​
6. 无标签直接跳过,不产生任何操作
2026-05-17 15:22:31 +08:00
ZhanGSKen 3707891e0b 1. 调用函数 → 查出模块标签 + 标签绑定提交Commit哈希
​
2. 判定标签/Commit为空直接跳过
​
3. 合并命令: git checkout origin/模块名  commit哈希:模块文件夹
​
4. 仅添加当前模块目录,精准提交
​
5. 提交日志同时记录标签名+提交哈希,方便回溯
2026-05-17 15:17:40 +08:00
ZhanGSKen 0c9c6c9fd4 1. 调试日志重定向  >&2
彻底杜绝调试文字混入标签变量, MOD_TAG  只存纯净标签名
​
2. 拉取标签写法修正
旧: git checkout 标签名 目录 
新: git checkout origin/tags/标签名 -- 目录 
直接从远程标签仓库拉取对应提交点文件夹,100%命中标签代码
​
3. 精准add提交
放弃  git add . ,只添加当前合并的模块文件夹,避免乱提交
​
4. 强制全量同步标签
脚本开头双重 fetch --tags ,保证本地能读取所有远程版本标签
​
5. 空标签直接拦截
匹配不到标签完全跳过,不产生空提交、无效覆盖
​
6. 严格锁定本地分支,防止合并错分支
2026-05-17 15:11:21 +08:00
ZhanGSKen be3d042ade 设置合并最新标签的模块文件夹。取消合并最新提交的文件夹。 2026-05-17 14:22:14 +08:00
qinglong 33dc49267e 合并 APPBase 项目, 调试:模块[appbase] 远程分支最新Commit = 74299bf9b2 2026-05-17 13:00:02 +08:00
ZhanGSKen e3166b639e 操作步骤调整 2026-05-17 12:13:50 +08:00
ZhanGSKen 3d26bbe090 提交内容整理 2026-05-17 12:08:22 +08:00
ZhanGSKen cd375cefc5 直接取远程分支 origin/xxx 最新全量 Commit,不限制子目录
​
2. 优化标签匹配:只要标签前缀是  模块名-  就匹配
​
3. 保留你原有全部脚本结构,只改  get_module_latest_tag  函数
2026-05-17 11:35:41 +08:00
ZhanGSKen 025c095bcd 提交备注自动带上标签名 2026-05-17 11:18:06 +08:00
ZhanGSKen c88a0a52a8 修复标签获取bug 2026-05-17 11:09:45 +08:00
ZhanGSKen dc4eeefa55 更正分支环境检测名称 2026-05-17 11:04:46 +08:00
ZhanGSKen c7d79e160b 添加Projects_Keeper_Tag仓库合并管理脚本 2026-05-17 10:50:04 +08:00
ZhanGSKen 68ebd0181b Merge branch 'projects-keeper' into winboll 2026-05-16 17:47:48 +08:00
qinglong 771f591a3a 合并 APPBase 项目 2026-05-16 17:30:01 +08:00
ZhanGSKen 2bf62a510a Merge branch 'projects-keeper' into winboll 2026-05-16 15:36:36 +08:00
ZhanGSKen 8aaec10d74 更新输出提示,区分合并的项目类型 2026-05-16 11:17:41 +08:00
ZhanGSKen a3d5031cdc 添加推送命令 2026-05-16 10:44:24 +08:00
ZhanGSKen 9a7f651d80 合并 APPBase 项目 2026-05-16 10:23:40 +08:00
ZhanGSKen ba3877f3cc 合并 WinBoLL 项目 2026-05-16 10:23:40 +08:00
ZhanGSKen 7e2f48f33a 添加projects-keeper分支项目自动合并脚本。 2026-05-16 10:23:05 +08:00
209 changed files with 4049 additions and 11125 deletions
@@ -0,0 +1,192 @@
#!/system/bin/sh
## 合并其他项目分支的模块源码到projects-keeper分支。
# ====================== 0. 进入目标目录 ======================
TARGET_DIR="/sdcard/AppProjects/Projects_Keeper"
echo "切换工作目录到:$TARGET_DIR"
if ! cd "$TARGET_DIR"; then
echo "=============================================="
echo "错误:无法进入目标目录 $TARGET_DIR"
echo "=============================================="
exit 1
fi
# ====================== 1. 拉取远程最新源码(失败直接退出) ======================
echo "=============================================="
echo "正在拉取远程最新源码..."
echo "=============================================="
if ! git pull; then
echo "=============================================="
echo "错误:拉取远程源码失败!"
echo "请检查网络、仓库冲突或手动处理 git 状态后再执行脚本。"
echo "=============================================="
exit 1
fi
echo "✅ 源码已拉取为最新状态"
echo ""
# ====================== 2. 目录路径检查 ======================
CUR_DIR=$(pwd)
if [ "$CUR_DIR" != "$TARGET_DIR" ]; then
echo "错误:当前目录不是项目根目录!"
echo "请先进入目录:$TARGET_DIR"
exit 1
fi
# ====================== 3. Git 分支检查 ======================
CUR_BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
TARGET_BRANCH="projects-keeper"
if [ "$CUR_BRANCH" != "$TARGET_BRANCH" ]; then
echo "错误:当前不在 $TARGET_BRANCH 分支!"
echo "当前分支:$CUR_BRANCH"
echo "请先执行:git checkout $TARGET_BRANCH"
exit 1
fi
# ====================== 4. 预设标准模块列表 ======================
MERGE_OBJECTS_LIST=(
.git
.gitignore
.gitmodules
.winboll
GenKeyStore
LICENSE
LICENSE-Private-Demo
LICENSE-Private-Demo_docs
README.md
aes
appbase
autonfc
build.gradle
contacts
debugtemp
gallery
gpsrelaysentinel
gradle
gradle.properties-android-demo
gradle.properties-androidx-demo
gradlew
libaes
libappbase
libdebugtemp
libgpsrelaysentinel
libwinboll
local.properties-demo
mymessagemanager
positions
powerbell
settings.gradle-demo
winboll
winboll.properties-demo
)
# ====================== 5. 获取当前目录真实文件列表 ======================
REAL_ITEMS=()
while IFS= read -r line; do
if [[ "$line" != "." && "$line" != ".." ]]; then
REAL_ITEMS+=("$line")
fi
done < <(ls -a)
# ====================== 6. 差异比对函数 ======================
check_diff() {
local missing=()
local extra=()
for item in "${MERGE_OBJECTS_LIST[@]}"; do
local found=0
for r in "${REAL_ITEMS[@]}"; do
if [[ "$item" == "$r" ]]; then
found=1
break
fi
done
if (( found == 0 )); then
missing+=("$item")
fi
done
for r in "${REAL_ITEMS[@]}"; do
local found=0
for item in "${MERGE_OBJECTS_LIST[@]}"; do
if [[ "$item" == "$r" ]]; then
found=1
break
fi
done
if (( found == 0 )); then
extra+=("$r")
fi
done
if [[ ${#missing[@]} -gt 0 || ${#extra[@]} -gt 0 ]]; then
echo "=============================================="
echo "【错误】合并环境与脚本预设列表不匹配!"
echo "请手动核对并修改合并脚本。"
echo "=============================================="
if [[ ${#missing[@]} -gt 0 ]]; then
echo -e "\n👉 本地缺失项目:"
for m in "${missing[@]}"; do echo " $m"; done
fi
if [[ ${#extra[@]} -gt 0 ]]; then
echo -e "\n👉 本地多余项目:"
for e in "${extra[@]}"; do echo " $e"; done
fi
echo -e "\n=============================================="
exit 1
fi
}
# 执行差异校验
check_diff
# ====================== 全部校验通过,继续执行合并 ======================
echo -e "#@@@ 开始合并模块源码 @@@#
## 目标合并对象列表:"
for item in "${MERGE_OBJECTS_LIST[@]}"; do
echo "$item"
done
echo -e "## 对象列表结束
"
## 合并 APP 项目
MERGE_APP_PROJECT_LIST=(
DemoAPP
)
echo -e "#@@@ 开始合并应用型模块源码 @@@#
## 目标合并对象列表:"
for item in "${MERGE_APP_PROJECT_LIST[@]}"; do
echo "正在合并 $item 项目 ..."
item_lower=$(echo "$item" | tr 'A-Z' 'a-z')
git checkout origin/$item_lower $item_lower
git add .
git commit -m "合并 $item 项目"
done
## 合并 LIB 项目
MERGE_LIB_PROJECT_LIST=(
WinBoLL
APPBase
AES
)
echo -e "#@@@ 开始合并类库型模块源码 @@@#
## 目标合并对象列表:"
for item in "${MERGE_LIB_PROJECT_LIST[@]}"; do
echo "正在合并 $item 项目 ..."
item_lower=$(echo "$item" | tr 'A-Z' 'a-z')
git checkout origin/$item_lower $item_lower lib$item_lower
git add .
git commit -m "合并 $item 项目"
done
echo '正在推送 Projects_Keeper 项目'
git push
@@ -0,0 +1,145 @@
#!/system/bin/sh
## 逻辑:按时间取最新标签 → 拉取该标签目录合并
# 按创建时间取模块最新标签(最新打的标签排最后)
get_latest_module_tag(){
local mod=$1
git for-each-ref --sort=-creatordate --format='%(refname)' refs/tags/${mod}-* \
| grep -v '\^{}' \
| head -1 \
| sed 's/refs\/tags\///'
}
# 通过标签获取commit
get_commit_from_tag(){
local tag=$1
git rev-parse --short "${tag}^{commit}"
}
# 工作目录
TARGET_DIR="/sdcard/AppProjects/Projects_Keeper_Tag"
echo "进入目录:${TARGET_DIR}"
cd "${TARGET_DIR}" || exit 1
# 同步远程
echo "========================================"
echo "同步远程分支与全部版本标签"
echo "========================================"
git fetch origin --prune
git fetch origin --tags
echo "同步完成"
echo ""
# 校验目标分支
NOW_BRANCH=$(git symbolic-ref --short HEAD)
TARGET_BRANCH="projects_keeper_tag"
if [ "${NOW_BRANCH}" != "${TARGET_BRANCH}" ];then
echo "错误:请先切换到 ${TARGET_BRANCH} 分支"
exit 1
fi
# 目录结构校验
MERGE_OBJECTS_LIST=(
.git
.gitignore
.gitmodules
.winboll
GenKeyStore
LICENSE
LICENSE-Private-Demo
LICENSE-Private-Demo_docs
README.md
aes
appbase
autonfc
build.gradle
contacts
debugtemp
gallery
gpsrelaysentinel
gradle
gradle.properties-android-demo
gradle.properties-androidx-demo
gradlew
libaes
libappbase
libdebugtemp
libgpsrelaysentinel
libwinboll
local.properties-demo
mymessagemanager
positions
powerbell
settings.gradle-demo
winboll
winboll.properties-demo
)
REAL_ITEMS=()
while IFS= read -r line; do
[[ $line != "." && $line != ".." ]] && REAL_ITEMS+=("$line")
done < <(ls -a)
check_diff(){
local miss=() extra=()
for i in "${MERGE_OBJECTS_LIST[@]}";do
[[ ! " ${REAL_ITEMS[@]} " =~ " ${i} " ]] && miss+=("$i")
done
for i in "${REAL_ITEMS[@]}";do
[[ ! " ${MERGE_OBJECTS_LIST[@]} " =~ " ${i} " ]] && extra+=("$i")
done
if [[ ${#miss[@]} -gt 0 || ${#extra[@]} -gt 0 ]];then
echo "本地目录结构不一致,终止运行"
exit 1
fi
}
check_diff
echo -e "#@@@ 按时间获取最新标签合并模块源码 @@@#"
# 应用型模块
MERGE_APP_PROJECT_LIST=(DemoAPP)
echo -e "---------- 应用型模块 ----------"
for name in "${MERGE_APP_PROJECT_LIST[@]}";do
low_name=$(echo "$name" | tr 'A-Z' 'a-z')
tag=$(get_latest_module_tag "${low_name}")
if [[ -z "${tag}" ]];then
echo "跳过 ${low_name}:无远程标签"
continue
fi
commit=$(get_commit_from_tag "${tag}")
if [[ -z "${commit}" ]];then
echo "跳过 ${low_name}:标签无有效提交点"
continue
fi
echo "模块:${low_name} 最新时间标签:${tag} 提交ID:${commit}"
# 强制拉取覆盖
git checkout -f "${tag}" -- "${low_name}"
git add "${low_name}"
git commit -m "合并模块${name} 同步最新时间标签${tag}"
done
# 类库模块
MERGE_LIB_PROJECT_LIST=(WinBoLL APPBase AES)
echo -e "---------- 类库模块 ----------"
for name in "${MERGE_LIB_PROJECT_LIST[@]}";do
low_name=$(echo "$name" | tr 'A-Z' 'a-z')
tag=$(get_latest_module_tag "${low_name}")
if [[ -z "${tag}" ]];then
echo "跳过 ${low_name}:无远程标签"
continue
fi
commit=$(get_commit_from_tag "${tag}")
if [[ -z "${commit}" ]];then
echo "跳过 ${low_name}:标签无有效提交点"
continue
fi
echo "模块:${low_name} 最新时间标签:${tag} 提交ID:${commit}"
git checkout -f "${tag}" -- "${low_name}" "lib${low_name}"
git add "${low_name}" "lib${low_name}"
git commit -m "合并模块${name} 同步最新时间标签${tag}"
done
echo "全部模块合并执行完毕"
echo "执行推送:git push"
git push
-201
View File
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+4 -4
View File
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue May 12 13:11:28 HKT 2026
stageCount=4
#Sun May 17 20:53:39 HKT 2026
stageCount=5
libraryProject=libaes
baseVersion=15.20
publishVersion=15.20.3
publishVersion=15.20.4
buildCount=0
baseBetaVersion=15.20.4
baseBetaVersion=15.20.5
+4 -4
View File
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue May 12 09:17:15 HKT 2026
stageCount=10
#Sun May 17 16:16:36 HKT 2026
stageCount=16
libraryProject=libappbase
baseVersion=15.20
publishVersion=15.20.9
publishVersion=15.20.15
buildCount=0
baseBetaVersion=15.20.10
baseBetaVersion=15.20.16
Vendored Regular → Executable
View File
+5
View File
@@ -21,6 +21,11 @@ android {
}
// 米盟 SDK
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
packagingOptions {
doNotStrip "*/*/libmimo_1011.so"
}
+4 -4
View File
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue May 12 13:11:09 HKT 2026
stageCount=4
#Sun May 17 20:53:39 HKT 2026
stageCount=5
libraryProject=libaes
baseVersion=15.20
publishVersion=15.20.3
publishVersion=15.20.4
buildCount=0
baseBetaVersion=15.20.4
baseBetaVersion=15.20.5
@@ -50,7 +50,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginTop="0dp"> <!-- 移除顶部多余间距 -- android:background="@drawable/bg_container_border">
android:layout_marginTop="0dp"> <!-- 移除顶部多余间距 - android:background="@drawable/bg_container_border" -->
<ImageView
android:id="@+id/iv_winboll_store"
+1 -1
View File
@@ -28,6 +28,6 @@
<color name="toolbarTextColor">#FFFFFFFF</color>
<color name="mainWindowBackgroundColor">#FF2C2C2C</color>
<color name="mainWindowTextColor">#FFFFFFFF</color>
<color name="debugTextColor">#FFFF0000</color>
<color name="debugTextColor">#FFAAAAAA</color>
</resources>
+1 -1
View File
@@ -28,6 +28,6 @@
<color name="toolbarTextColor">#FFFFFFFF</color>
<color name="mainWindowBackgroundColor">#FFFFFFFF</color>
<color name="mainWindowTextColor">#FF000000</color>
<color name="debugTextColor">#FFFF0000</color>
<color name="debugTextColor">#FF808080</color>
</resources>
-9
View File
@@ -25,14 +25,5 @@ android {
}
dependencies {
// 网络连接类库
api 'com.squareup.okhttp3:okhttp:4.4.1'
// Gson
api 'com.google.code.gson:gson:2.8.9'
// Html 解析
api 'org.jsoup:jsoup:1.13.1'
// 添加JSch依赖(SFTP核心,com.jcraft:jsch:0.1.54
api 'com.jcraft:jsch:0.1.54'
api fileTree(dir: 'libs', include: ['*.jar'])
}
+4 -4
View File
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue May 12 09:16:45 HKT 2026
stageCount=10
#Sun May 17 16:16:36 HKT 2026
stageCount=16
libraryProject=libappbase
baseVersion=15.20
publishVersion=15.20.9
publishVersion=15.20.15
buildCount=0
baseBetaVersion=15.20.10
baseBetaVersion=15.20.16
-12
View File
@@ -3,18 +3,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.libappbase">
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 读取您共享存储空间中的内容 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 修改或删除您共享存储空间中的内容 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- MANAGE_EXTERNAL_STORAGE -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<application
android:requestLegacyExternalStorage="true"
android:networkSecurityConfig="@xml/network_security_config">
@@ -135,8 +135,8 @@ public class LogUtils {
return;
}
final long MAX_FILE_SIZE = 6291456L;
final long KEEP_FILE_SIZE = 3145728L;
final long KEEP_FILE_SIZE = 25000L; // ~25KB 确保剪贴板可完整复制
final long MAX_FILE_SIZE = 2*KEEP_FILE_SIZE;
final long fileSize = _mfLogCatchFile.length();
if (fileSize <= MAX_FILE_SIZE) {
@@ -12,13 +12,11 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.R;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.libappbase.dialogs.DebugHostDialog;
import cc.winboll.studio.libappbase.dialogs.APPValidationDialog;
import cc.winboll.studio.libappbase.models.APPInfo;
/**
@@ -328,14 +326,7 @@ public class AboutView extends LinearLayout {
ToastUtils.show("已取消调试状态,重启应用可生效。");
}
});
// 正版校验弹窗
ibSigngetDialog.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.d(TAG, "ibSigngetDialog onClick:唤起应用正版校验弹窗");
new APPValidationDialog(mContext, mszAppName, mszAppVersionName).show();
}
});
// 调试地址配置弹窗
ibWinBoLLHostDialog.setOnClickListener(new OnClickListener() {
@Override
-1
View File
@@ -1 +0,0 @@
/build
-42
View File
@@ -1,42 +0,0 @@
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply from: '../.winboll/winboll_lib_build.gradle'
apply from: '../.winboll/winboll_lint_build.gradle'
android {
// 适配MIUI12
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
minSdkVersion 26
targetSdkVersion 30
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
// 网络连接类库
api 'com.squareup.okhttp3:okhttp:4.4.1'
// Gson
api 'com.google.code.gson:gson:2.8.9'
// Html 解析
api 'org.jsoup:jsoup:1.13.1'
// 添加JSch依赖(SFTP核心,com.jcraft:jsch:0.1.54
api 'com.jcraft:jsch:0.1.54'
// WinBoLL库 nexus.winboll.cc 地址
api 'cc.winboll.studio:libaes:15.20.3'
api 'cc.winboll.studio:libappbase:15.20.9'
api fileTree(dir: 'libs', include: ['*.jar'])
}
-8
View File
@@ -1,8 +0,0 @@
#Created by .winboll/winboll_app_build.gradle
#Fri May 15 08:48:45 GMT 2026
stageCount=2
libraryProject=libwinboll
baseVersion=15.20
publishVersion=15.20.1
buildCount=7
baseBetaVersion=15.20.2
-17
View File
@@ -1,17 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:/tools/adt-bundle-windows-x86_64-20131030/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.libwinboll" >
<application>
<activity
android:name=".WinBoLLLibraryActivity">
</activity>
</application>
</manifest>
@@ -1,17 +0,0 @@
package cc.winboll.studio.libwinboll;
import android.app.Activity;
import android.os.Bundle;
import cc.winboll.studio.libappbase.ToastUtils;
public class WinBoLLLibraryActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_winbolllibrary);
ToastUtils.show("WinBoLLLibraryActivity onCreate");
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

@@ -1,11 +0,0 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cc.winboll.studio.libwinboll.WinBoLLLibraryActivity"/>
</LinearLayout>
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@android:style/Theme.Material.Light">
</style>
</resources>
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="lib_name">libwinboll</string>
<string name="hello_world">Hello world!</string>
</resources>
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@android:style/Theme.Holo.Light">
</style>
</resources>
+4
View File
@@ -96,3 +96,7 @@
// AutoNFC 项目编译设置
//include ':autonfc'
//rootProject.name = "autonfc"
// StallHelper 项目编译设置
//include ':stallhelper'
//rootProject.name = "stallhelper"
+4
View File
@@ -0,0 +1,4 @@
# StallHelper
# 排档辅助管理工具
## LargeStall Stand Auxiliary Management Tool.
@@ -18,44 +18,33 @@ def genVersionName(def versionName){
}
android {
// MIUI12
compileSdkVersion 30
buildToolsVersion "30.0.3"
compileSdkVersion 30
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
defaultConfig {
applicationId "cc.winboll.studio.winboll"
applicationId "cc.winboll.studio.stallhelper"
minSdkVersion 26
// MIUI12
targetSdkVersion 30
versionCode 1
// versionName
// .winboll/winbollBuildProps.properties stageCount=0
// Gradle编译环境下合起来的 versionName "${versionName}.0"
versionName "15.20"
versionName "15.20"
if(true) {
versionName = genVersionName("${versionName}")
}
}
// SDK
packagingOptions {
doNotStrip "*/*/libmimo_1011.so"
}
sourceSets {
main {
jniLibs.srcDirs = ['libs'] // SO库放在libs目录下
}
}
}
dependencies {
api project(':libwinboll')
api 'com.google.code.gson:gson:2.10.1'
//
//
api 'com.baoyz.pullrefreshlayout:library:1.2.0'
//
// https://mvnrepository.com/artifact/com.github.open-android/pinyin4j
api 'com.github.open-android:pinyin4j:2.5.0'
// SSH
api 'com.jcraft:jsch:0.1.55'
// Html
@@ -65,44 +54,27 @@ dependencies {
api 'com.journeyapps:zxing-android-embedded:3.6.0'
//
api 'io.github.medyo:android-about-page:2.0.0'
//
//
api 'com.squareup.okhttp3:okhttp:4.4.1'
// FastJSON解析
implementation 'com.alibaba:fastjson:1.2.76'
// AndroidX
/*api 'androidx.appcompat:appcompat:1.1.0'
// AndroidX
api 'androidx.appcompat:appcompat:1.1.0'
api 'androidx.cardview:cardview:1.0.0'
//api 'com.google.android.material:material:1.4.0'
//api 'androidx.viewpager:viewpager:1.0.0'
//api 'androidx.vectordrawable:vectordrawable:1.1.0'
//api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
//api 'androidx.fragment:fragment:1.1.0'*/
//api 'androidx.fragment:fragment:1.1.0'
//
api 'com.miui.zeus:mimo-ad-sdk:5.3.+'//使sdk
//5
//5
//implementation 'androidx.appcompat:appcompat:1.4.1'
api 'androidx.recyclerview:recyclerview:1.0.0'
api 'com.google.code.gson:gson:2.8.5'
api 'com.github.bumptech.glide:glide:4.9.0'
//annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
implementation "androidx.annotation:annotation:1.3.0"
implementation "androidx.core:core:1.6.0"
implementation "androidx.drawerlayout:drawerlayout:1.1.1"
implementation "androidx.preference:preference:1.1.1"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "com.google.android.material:material:1.4.0"
implementation "com.google.guava:guava:24.1-jre"
/*
implementation "io.noties.markwon:core:$markwonVersion"
implementation "io.noties.markwon:ext-strikethrough:$markwonVersion"
implementation "io.noties.markwon:linkify:$markwonVersion"
implementation "io.noties.markwon:recycler:$markwonVersion"
*/
implementation 'com.termux:terminal-emulator:0.118.0'
implementation 'com.termux:terminal-view:0.118.0'
implementation 'com.termux:termux-shared:0.118.0'
// WinBoLL库 nexus.winboll.cc
api 'cc.winboll.studio:libaes:15.20.4'
api 'cc.winboll.studio:libappbase:15.20.15'
api fileTree(dir: 'libs', include: ['*.jar'])
}
+8
View File
@@ -0,0 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Fri May 22 19:00:55 HKT 2026
stageCount=6
libraryProject=
baseVersion=15.20
publishVersion=15.20.5
buildCount=0
baseBetaVersion=15.20.6
@@ -67,6 +67,12 @@
-keep class okio.** { *; }
-dontwarn okhttp3.internal.platform.**
-dontwarn okio.**
# ============================== 必要补充规则 ==============================
# OkHttp 4.4.1 补充规则(Java 7 兼容)
-keep class okhttp3.internal.concurrent.** { *; }
-keep class okhttp3.internal.connection.** { *; }
-dontwarn okhttp3.internal.concurrent.TaskRunner
-dontwarn okhttp3.internal.connection.RealCall
# Glide 4.9.0(米盟广告图片加载依赖)
-keep public class * implements com.bumptech.glide.module.GlideModule
@@ -3,8 +3,9 @@
xmlns:tools="http://schemas.android.com/tools" >
<application
tools:replace="android:icon"
android:icon="@drawable/ic_launcher_beta">
android:icon="@drawable/ic_stall_beta">
<!-- Put flavor specific code here -->
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">排档辅助管理工具+</string>
</resources>
@@ -1,3 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">StallHelper+</string>
</resources>
+51
View File
@@ -0,0 +1,51 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.stallhelper">
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".App"
android:allowBackup="true"
android:icon="@drawable/ic_stall"
android:label="@string/app_name"
android:theme="@style/MyStallHelperTheme"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="standard"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".activities.AboutActivity"
android:label="AboutActivity"/>
<activity
android:name="cc.winboll.studio.stallhelper.activities.PreNullDiningTableActivity"
android:windowSoftInputMode="adjustResize"/>
<activity
android:name="cc.winboll.studio.stallhelper.activities.CompleteDiningTableActivity"
android:windowSoftInputMode="adjustResize"/>
<activity android:name="cc.winboll.studio.stallhelper.activities.NoteRecordHelperActivity"/>
<activity android:name="cc.winboll.studio.stallhelper.activities.TaskSchedulerActivity"/>
</application>
</manifest>
@@ -0,0 +1,36 @@
package cc.winboll.studio.stallhelper;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/01/22 00:11:41
* @Describe 全局应用类
*/
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.libappbase.BuildConfig;
public class App extends GlobalApplication {
public static final String TAG = "App";
@Override
public void onCreate() {
super.onCreate();
if (isDebugging() != true) {
setIsDebugging(BuildConfig.DEBUG);
}
//setIsDebugging(false);
WinBoLLActivityManager.init(this);
// 初始化 Toast 框架
ToastUtils.init(this);
}
@Override
public void onTerminate() {
super.onTerminate();
ToastUtils.release();
}
}
@@ -0,0 +1,135 @@
package cc.winboll.studio.stallhelper;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.stallhelper.R;
import cc.winboll.studio.stallhelper.activities.AboutActivity;
import cc.winboll.studio.stallhelper.activities.CompleteDiningTableActivity;
import cc.winboll.studio.stallhelper.activities.NoteRecordHelperActivity;
import cc.winboll.studio.stallhelper.activities.PreNullDiningTableActivity;
import cc.winboll.studio.stallhelper.activities.TaskSchedulerActivity;
import cc.winboll.studio.stallhelper.activities.WinBoLLActivity;
final public class MainActivity extends WinBoLLActivity {
public static final String TAG = "MainActivity";
public static final int REQUEST_HOME_ACTIVITY = 0;
public static final int REQUEST_ABOUT_ACTIVITY = 1;
Context mContext;
private Toolbar mToolbar;
// @Override
// protected boolean isEnableDisplayHomeAsUp() {
// return false;
// }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = getApplicationContext();
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
}
@Override
public String getTag() {
return TAG;
}
// @Override
// protected boolean isAddWinBoLLToolBar() {
// return true;
// }
//
// @Override
// protected Toolbar initToolBar() {
// return findViewById(R.id.activitymainToolbar1);
// }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_about) {
startActivity(new Intent(this, AboutActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
void openAboutActivity() {
Intent intent = new Intent(getApplicationContext(), AboutActivity.class);
startActivity(intent);
//App.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), AboutActivity.class);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (resultCode) {
case REQUEST_HOME_ACTIVITY : {
LogUtils.d(TAG, "REQUEST_HOME_ACTIVITY");
break;
}
case REQUEST_ABOUT_ACTIVITY : {
LogUtils.d(TAG, "REQUEST_ABOUT_ACTIVITY");
break;
}
default : {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
public void onPreNullDiningTable(View view) {
//ToastUtils.show("onDiningTable");
Intent intent = new Intent(getApplicationContext(), PreNullDiningTableActivity.class);
startActivity(intent);
//App.getWinBoLLActivityManager().startWinBoLLActivity(mContext, PreNullDiningTableActivity.class);
// try {
// WinBoLLActivity clazzActivity = PreNullDiningTableActivity.class.newInstance();
// String tag = clazzActivity.getTag();
// LogUtils.d(TAG, "String tag = clazzActivity.getTag(); tag " + tag);
// Intent intent = new Intent(getApplicationContext(), PreNullDiningTableActivity.class);
// startWinBoLLActivity(intent, tag);
// } catch (IllegalAccessException e) {} catch (InstantiationException e) {}
}
public void onCompleteDiningTable(View view) {
//ToastUtils.show("onDiningTable");
Intent intent = new Intent(getApplicationContext(), CompleteDiningTableActivity.class);
startActivity(intent);
//App.getWinBoLLActivityManager().startWinBoLLActivity(mContext, CompleteDiningTableActivity.class);
// try {
// WinBoLLActivity clazzActivity = CompleteDiningTableActivity.class.newInstance();
// String tag = clazzActivity.getTag();
// LogUtils.d(TAG, "String tag = clazzActivity.getTag(); tag " + tag);
// Intent intent = new Intent(getApplicationContext(), CompleteDiningTableActivity.class);
// startWinBoLLActivity(intent, tag);
// } catch (IllegalAccessException e) {} catch (InstantiationException e) {}
}
public void onNoteRecordHelper(View view) {
Intent intent = new Intent(getApplicationContext(), NoteRecordHelperActivity.class);
startActivity(intent);
}
public void onTaskScheduler(View view) {
Intent intent = new Intent(getApplicationContext(), TaskSchedulerActivity.class);
startActivity(intent);
}
}
@@ -0,0 +1,50 @@
package cc.winboll.studio.stallhelper.activities;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.widget.Toolbar;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.stallhelper.R;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.models.APPInfo;
import cc.winboll.studio.libappbase.views.AboutView;
/**
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @Date 2026/01/11 12:55
* @Describe AboutActivity
*/
public class AboutActivity extends AppCompatActivity {
public static final String TAG = "AboutActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
AboutView aboutView = findViewById(R.id.aboutview);
aboutView.setAPPInfo(genDefaultAppInfo());
}
private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo() 调用");
String branchName = "stallhelper";
APPInfo appInfo = new APPInfo();
appInfo.setAppName("StallHelper");
appInfo.setAppIcon(R.drawable.ic_winboll);
appInfo.setAppDescription(getString(R.string.app_description));
appInfo.setAppGitName("StallHelper");
appInfo.setAppGitOwner("ZhanGSKen");
appInfo.setAppGitAPPBranch(branchName);
appInfo.setAppGitAPPSubProjectFolder(branchName);
appInfo.setAppHomePage("http://10.8.0.4:9876/apks/index-manager.php?project=StallHelper");
appInfo.setAppAPKName("StallHelper");
appInfo.setAppAPKFolderName("StallHelper");
LogUtils.d(TAG, "genDefaultAppInfo: 应用信息已生成");
return appInfo;
}
}
@@ -0,0 +1,371 @@
package cc.winboll.studio.stallhelper.activities;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/10/29 09:22:24
* @Describe 餐桌表补全窗口
*/
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.stallhelper.App;
import cc.winboll.studio.stallhelper.R;
import cc.winboll.studio.stallhelper.beans.DiningTableBean;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
public class CompleteDiningTableActivity extends WinBoLLActivity {
public static final String TAG = "CompleteDiningTableActivity";
// 某一号晚上的餐桌预定补全列表
ArrayList<DiningTableBean> mCompleteTableInfoList;
// 原始预定信息内容输入框
EditText metOriginBookText;
EditText metPreBookList;
EditText metCompleteDate;
ScrollView mScrollView;
ArrayList<String> mszOriginBookList;
@Override
public String getTag() {
return TAG;
}
// @Override
// protected boolean isEnableDisplayHomeAsUp() {
// return true;
// }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_completediningtable);
setTitle("餐桌表补全");
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
StringBuilder sbDateNow = new StringBuilder("当前日期:");
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeString = sdf.format(now);
sbDateNow.append(timeString);
TextView tvDateNow = findViewById(R.id.activitycompletediningtableTextView2);
tvDateNow.setText(sbDateNow.toString());
metOriginBookText = findViewById(R.id.activitycompletediningtableEditText1);
metPreBookList = findViewById(R.id.activitycompletediningtableEditText2);
metCompleteDate = findViewById(R.id.activitycompletediningtableEditText3);
mScrollView = findViewById(R.id.activitycompletediningtableScrollView1);
}
// @Override
// protected Toolbar initToolBar() {
// return findViewById(R.id.activitycompletediningtableToolbar1);
// }
//
// @Override
// protected boolean isAddWinBoLLToolBar() {
// return false;
// }
boolean isInCompleteRule(DiningTableBean item) {
String szCompleteDate = metCompleteDate.getText().toString() + "";
if (item.getDate().equals(szCompleteDate) && item.getDinnerType() == DiningTableBean.DinnerType.Evening) {
return true;
}
return false;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
WinBoLLActivityManager.getInstance().finish(this);
}
return super.onOptionsItemSelected(item);
}
void createNullCompleteTableInfoList() {
mCompleteTableInfoList = new ArrayList<DiningTableBean>();
String szCompleteDate = metCompleteDate.getText().toString() + "";
mCompleteTableInfoList.add(new DiningTableBean("201", 18, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("202", 8, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("203", 8, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("205", 10, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("206", 0, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("207", 0, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("208", 8, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("209", 10, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("210", 8, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("211", 12, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("212", 8, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("213", 9, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("666", 14, true, szCompleteDate));
mCompleteTableInfoList.add(new DiningTableBean("888", 20, true, szCompleteDate));
for (int i = 1; i < 23; i++) {
DiningTableBean tempBean = new DiningTableBean(Integer.toString(i), 0, true, szCompleteDate);
tempBean.setDinnerType(DiningTableBean.DinnerType.Evening);
tempBean.setTableType(DiningTableBean.TableType.Table);
tempBean.setIsSelected(false);
mCompleteTableInfoList.add(tempBean);
}
//DiningTableBean.saveBeanListToFile(getApplicationContext().getExternalFilesDir("temp") + "/1.json", mCompleteTableInfoList);
//ToastUtils.show("Test");
}
ArrayList<DiningTableBean> getOriginBookList() {
//ToastUtils.show(metOriginBookText.getText().toString());
ArrayList<DiningTableBean> listReturn = new ArrayList<DiningTableBean>();
String[] szOriginBookText = metOriginBookText.getText().toString().split("\\r?\\n");
for (String szTemp : szOriginBookText) {
String szTemp2 = szTemp.replace(" ", "");
DiningTableBean bean = format2DiningTableBean(szTemp2);
if (bean != null) {
listReturn.add(bean);
// 更新补全列表
updateCompleteTableInfoList(bean);
}
}
//ToastUtils.show("szOriginBookText : " + Integer.toString(szOriginBookText.length));
//ToastUtils.show("listReturn : " + Integer.toString(listReturn.size()));
return listReturn;
}
//
// 如果补全列表某一项时间和房号与指定项一致,
// 就把指定项信息更新至补全列表中。
//
void updateCompleteTableInfoList(DiningTableBean beanNew) {
for (DiningTableBean completeTableInfo : mCompleteTableInfoList) {
if (completeTableInfo.getDate().equals(beanNew.getDate())
&& completeTableInfo.getDinnerType() == beanNew.getDinnerType()
&& completeTableInfo.getTableNumber().equals(beanNew.getTableNumber())) {
completeTableInfo.setBookDesc(beanNew.getBookDesc());
completeTableInfo.setIsSelected(true);
}
}
}
//
// 检验每一个数据行的日期格式,
// 如果出现(x号/x月x号)以外的日期标注,
// 则提示有数据行日期标识不清晰的情况。
//
boolean checkLinesDateValidAndShow() {
boolean checkResult = true;
String[] szLines = metOriginBookText.getText().toString().split("\\r?\\n");
if (szLines.length < 1) {
ToastUtils.show("没有数据行。");
checkResult = false;
} else {
StringBuilder sb = new StringBuilder("日期标识不清晰,在");
for (int i = 0; i < szLines.length; i++) {
Pattern pattern = Pattern.compile("(\\d*[月]{0,1}\\d+号)\\s*([晚|午]{0,1}).*");
Matcher matcher = pattern.matcher(szLines[i]);
if (!matcher.find()) {
sb.append("(");
sb.append(Integer.toString(i + 1));
sb.append(")");
checkResult = false;
}
}
sb.append("行。");
if (checkResult == false) {
ToastUtils.show(sb.toString());
}
}
return checkResult;
}
//
// 获取指定日期的第一条数据的位置
// 返回 -1 表示所有数据都没有该日期
//
int getFirstIndexOfDate(ArrayList<DiningTableBean> originBookList, String szDate) {
int nResult = -1;
//ToastUtils.show("szDate " + szDate);
for (int i = originBookList.size() - 1 ; i > 0; i--) {
//LogUtils.d(TAG, "originBookList.get(i).getDate() " + originBookList.get(i).getDate());
if (originBookList.get(i).isDiningTableBean()) {
if (originBookList.get(i).getDate().equals(szDate)) {
nResult = i;
continue;
} else {
return nResult;
}
} else {
nResult = i;
continue;
}
}
return nResult;
}
DiningTableBean format2DiningTableBean(String szBookInfo) {
if (!szBookInfo.trim().equals("")) {
//String sz = "29号晚 201房 123456";
// 定义正则表达式模式
Pattern pattern = Pattern.compile("(\\d*[月]{0,1}\\d+号)\\s*([晚|午]{0,1})\\s*(\\d+)([房|桌])[-\\s]*(.*)");
Matcher matcher = pattern.matcher(szBookInfo);
if (matcher.find()) {
String date = matcher.group(1);
String szDinnerType = matcher.group(2);
String tableNumber = matcher.group(3);
String szTableType = matcher.group(4);
String bookDesc = matcher.group(5);
DiningTableBean.DinnerType dinnerType = DiningTableBean.DinnerType.Evening;
if (szDinnerType.equals("")) {
dinnerType = DiningTableBean.DinnerType.Noon;
}
DiningTableBean.TableType tableType = DiningTableBean.TableType.Room;
if (szTableType.equals("")) {
tableType = DiningTableBean.TableType.Table;
}
return new DiningTableBean(tableNumber, 0, true, dinnerType, bookDesc, date, tableType);
} else {
return new DiningTableBean(true, false, szBookInfo);
}
}
return null;
}
void checkAndAddCompleteTableInfoList(ArrayList<DiningTableBean> originBookList) {
boolean isAddCompleteTableInfoList = false;
for (int i = 0; i < originBookList.size(); i++) {
DiningTableBean item = originBookList.get(i);
// 循环读取原始 Bean 列表,
// 如果遇到第一个匹配指定日期号,
// 就不显示 item 项,并且添加预制好的补全表(一次性添加,后续再遇到同类 item 项则不添加补全表。)。
if (isInCompleteRule(item)) {
// 设置不显示 item 项
item.setIsSelected(false);
// 添加补全列表(一次性添加,后续再遇到同类 item 项则不添加补全表。)
if (isAddCompleteTableInfoList == false) {
originBookList.addAll(i, mCompleteTableInfoList);
// 设置后续遇到同类项时,不再添加补全列表
isAddCompleteTableInfoList = true;
i = i + mCompleteTableInfoList.size();
}
}
}
// 如果遍历完原始 Bean 表后还未添加补全表,
// 就添加一次补全表
if (isAddCompleteTableInfoList == false) {
int nInsertPost = getFirstIndexOfDate(originBookList, metCompleteDate.getText().toString() + "");
//ToastUtils.show("nInsertPost " + Integer.toString(nInsertPost));
if (nInsertPost == -1) {
originBookList.addAll(mCompleteTableInfoList);
} else {
originBookList.addAll(nInsertPost, mCompleteTableInfoList);
}
// 设置后续遇到同类项时,不再添加补全列表
isAddCompleteTableInfoList = true;
}
}
public void onCopyResultText(View view) {
// Gets a handle to the clipboard service.
ClipboardManager clipboard = (ClipboardManager) getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE);
// Creates a new text clip to put on the clipboard
ClipData clip = ClipData.newPlainText("simple text", metPreBookList.getText());
// Set the clipboard's primary clip.
clipboard.setPrimaryClip(clip);
Toast.makeText(getApplicationContext(), "Copy to clipboard.", Toast.LENGTH_SHORT).show();
}
public void onCleanResultText(View view) {
metPreBookList.setText("");
}
public void onCreatePreBookList(View view) {
if(metCompleteDate.getText().toString().trim().equals("")) {
ToastUtils.show("没有填写补全日期");
return;
}
//checkLinesDateValidAndShow();
createNullCompleteTableInfoList();
ArrayList<DiningTableBean> originBookList = getOriginBookList();
checkAndAddCompleteTableInfoList(originBookList);
StringBuilder sbPreBookList = new StringBuilder();
for (int i = 0; i < originBookList.size(); i++) {
DiningTableBean item = originBookList.get(i);
if (item.isDiningTableBean()) {
if (item.getIsSelected()) {
String szDinnerTyp = "";
if (item.getDinnerType() == DiningTableBean.DinnerType.Evening) {
szDinnerTyp = "";
}
if (item.getDinnerType() == DiningTableBean.DinnerType.Noon) {
szDinnerTyp = "";
}
String szTableType = "";
if (item.getTableType() == DiningTableBean.TableType.Room) {
szTableType = "";
}
if (item.getTableType() == DiningTableBean.TableType.Table) {
szTableType = "";
}
sbPreBookList.append(item.getDate());
//sbPreBookList.append("号");
sbPreBookList.append(szDinnerTyp);
//sbPreBookList.append(" ");
sbPreBookList.append(item.getTableNumber());
sbPreBookList.append(szTableType);
sbPreBookList.append("-");
sbPreBookList.append(item.getBookDesc());
sbPreBookList.append("\n");
}
} else {
sbPreBookList.append(item.getOriginDesc());
sbPreBookList.append("\n");
}
// 不同日期间隔行排版
if (i + 1 != originBookList.size()) {
if (!originBookList.get(i + 1).getDate().equals(originBookList.get(i).getDate())) {
sbPreBookList.append("\n");
}
}
}
//metPreBookList.append("\n");
metPreBookList.append(sbPreBookList.toString());
mScrollView.post(new Runnable() {
@Override
public void run() {
mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
}
}
@@ -0,0 +1,226 @@
package cc.winboll.studio.stallhelper.activities;
import android.graphics.Color;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.BackgroundColorSpan;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.stallhelper.R;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @CreateTime 2026-03-31 00:20:00
* @ModifyTime 2026-03-31 14:47:00
* @Describe 订单笔录辅助窗口,支持房号、桌号、多房间号(含"号"字)、手机号尾4位及'-'后文本高亮,原文完整输出
*/
public class NoteRecordHelperActivity extends AppCompatActivity {
public static final String TAG = "NoteRecordHelperActivity";
// 高亮颜色数组
private final int[] highlightColors = {
Color.parseColor("#4CAF50"),
Color.parseColor("#FF9800"),
Color.parseColor("#E91E63"),
Color.parseColor("#F44336"),
Color.parseColor("#FFC107"),
Color.parseColor("#2196F3")
};
// 正则匹配
// 匹配多房间号(包含后面的"号"字):11-16-17号
private final Pattern PATTERN_MULTI_ROOM = Pattern.compile("(\\d+(?:-\\d+)+\\s*号)");
// 匹配手机号(连续11位或带分隔符)
private final Pattern PATTERN_PHONE = Pattern.compile("(?:\\d{11}|(?:\\d{3,4}[\\s-]?){3,4})");
// 控件
private EditText etContent;
private Button btnHighlight;
private TextView tvHighlightResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_noterecordhelper);
LogUtils.i(TAG, "onCreate: 页面初始化");
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
setTitle("订单笔录辅助");
initViews();
}
/**
* 初始化控件
*/
private void initViews() {
etContent = findViewById(R.id.et_content);
btnHighlight = findViewById(R.id.btn_highlight);
tvHighlightResult = findViewById(R.id.tv_highlight_result);
btnHighlight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.i(TAG, "onClick: 点击高亮按钮");
highlightContent();
}
});
}
/**
* 解析并高亮内容
*/
private void highlightContent() {
LogUtils.i(TAG, "highlightContent: 开始处理高亮");
String raw = etContent.getText().toString();
if (raw.isEmpty()) {
LogUtils.i(TAG, "highlightContent: 输入内容为空,直接返回");
return;
}
String[] lines = raw.split("\\n");
SpannableStringBuilder ssb = new SpannableStringBuilder();
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
// 空行也完整保留
if (line.isEmpty()) {
ssb.append("\n");
continue;
}
int colorIndex = i % highlightColors.length;
int color = highlightColors[colorIndex];
LogUtils.d(TAG, "highlightContent: 处理第" + (i + 1) + "行,颜色索引=" + colorIndex);
processLine(line, ssb, color);
if (i != lines.length - 1) {
ssb.append("\n");
}
}
tvHighlightResult.setText(ssb);
LogUtils.i(TAG, "highlightContent: 高亮处理完成");
}
/**
* 处理单行高亮(原文完整保留)
* @param line 单行文本
* @param ssb 富文本构建器
* @param color 高亮颜色
*/
private void processLine(String line, SpannableStringBuilder ssb, int color) {
LogUtils.d(TAG, "processLine: line=" + line + ", color=" + Integer.toHexString(color));
// 1. 先把原文完整追加到 ssb,不会丢失任何字符
int start = ssb.length();
ssb.append(line);
// 2. 高亮多房间号(包含"号"字):11-16-17号
Matcher mMulti = PATTERN_MULTI_ROOM.matcher(line);
if (mMulti.find()) {
int s = start + mMulti.start(1);
int e = start + mMulti.end(1);
ssb.setSpan(new BackgroundColorSpan(color), s, e, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
// 3. 高亮房号 / 桌号
int roomIdx = line.indexOf("");
int tableIdx = line.indexOf("号桌");
if (roomIdx != -1) {
int s = findNumberStart(line, roomIdx);
int e = roomIdx + 1;
ssb.setSpan(new BackgroundColorSpan(color), start + s, start + e, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (tableIdx != -1) {
int s = findNumberStart(line, tableIdx);
int e = tableIdx + 2;
ssb.setSpan(new BackgroundColorSpan(color), start + s, start + e, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
// 4. 处理'-'后的内容:优先高亮手机号尾4位,否则高亮全部文本
int dashIndex = line.indexOf("-");
if (dashIndex != -1) {
String afterDash = line.substring(dashIndex + 1);
Matcher phoneMatcher = PATTERN_PHONE.matcher(afterDash);
boolean foundPhone = false;
// 尝试匹配手机号并高亮尾4位
while (phoneMatcher.find()) {
String phone = phoneMatcher.group();
if (phone != null) {
foundPhone = true;
// 提取纯数字
String pureNumber = phone.replaceAll("[^0-9]", "");
if (pureNumber.length() >= 4) {
String last4 = pureNumber.substring(pureNumber.length() - 4);
// 在原行中定位尾4位(从 dashIndex+1 开始查找,避免匹配前面的数字)
int tailStart = line.indexOf(last4, dashIndex + 1);
if (tailStart != -1) {
int s = start + tailStart;
int e = s + 4;
ssb.setSpan(new BackgroundColorSpan(color), s, e, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
}
// 没有手机号,则高亮'-'后的全部文本
if (!foundPhone) {
int s = start + dashIndex + 1;
int e = start + line.length();
ssb.setSpan(new BackgroundColorSpan(color), s, e, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} else {
// 无'-'的行,尝试匹配并高亮手机号尾4位
Matcher phoneMatcher = PATTERN_PHONE.matcher(line);
while (phoneMatcher.find()) {
String phone = phoneMatcher.group();
if (phone != null) {
String pureNumber = phone.replaceAll("[^0-9]", "");
if (pureNumber.length() >= 4) {
String last4 = pureNumber.substring(pureNumber.length() - 4);
int tailStart = line.indexOf(last4);
if (tailStart != -1) {
int s = start + tailStart;
int e = s + 4;
ssb.setSpan(new BackgroundColorSpan(color), s, e, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
}
}
}
/**
* 查找数字起始位置
* @param line 文本行
* @param endIdx 结束位置
* @return 数字起始下标
*/
private int findNumberStart(String line, int endIdx) {
LogUtils.d(TAG, "findNumberStart: endIdx=" + endIdx);
for (int i = endIdx - 1; i >= 0; i--) {
char c = line.charAt(i);
if (!Character.isDigit(c) && c != ' ') {
return i + 1;
}
}
return 0;
}
}
@@ -0,0 +1,264 @@
package cc.winboll.studio.stallhelper.activities;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/10/16 05:13:42
* @Describe 餐桌空白预定表生成窗口
*/
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.stallhelper.R;
import cc.winboll.studio.stallhelper.beans.DiningTableBean;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
public class PreNullDiningTableActivity extends WinBoLLActivity {
public static final String TAG = "DiningTableActivity";
ArrayList<DiningTableBean> mListTableInfo;
DiningTableBeanListAdapter mDiningTableBeanListAdapter;
EditText metPreBookList;
ScrollView mScrollView;
RadioButton mrbDinnerTypeNoon;
RadioButton mrbDinnerTypeEvening;
@Override
public String getTag() {
return TAG;
}
// @Override
// protected boolean isEnableDisplayHomeAsUp() {
// return true;
// }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_prenulldiningtable);
setTitle("餐桌空白预定表制作");
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
StringBuilder sbDateNow = new StringBuilder("当前日期:");
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeString = sdf.format(now);
sbDateNow.append(timeString);
TextView tvDateNow = findViewById(R.id.activityprenulldiningtableTextView2);
tvDateNow.setText(sbDateNow.toString());
LocalDate currentDate = LocalDate.now();
int dayOfMonth = currentDate.getDayOfMonth();
EditText etDateNow = findViewById(R.id.activityprenulldiningtableEditText1);
etDateNow.setText(Integer.toString(dayOfMonth));
mListTableInfo = new ArrayList<DiningTableBean>();
addTable();
RecyclerView recyclerView = findViewById(R.id.activityprenulldiningtableRecyclerView1);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.HORIZONTAL, false));
mDiningTableBeanListAdapter = new DiningTableBeanListAdapter(mListTableInfo);
// 设置 RecyclerView 的适配器
recyclerView.setAdapter(mDiningTableBeanListAdapter);
metPreBookList = findViewById(R.id.activityprenulldiningtableEditText2);
mScrollView = findViewById(R.id.activityprenulldiningtableScrollView1);
mrbDinnerTypeNoon = findViewById(R.id.activityprenulldiningtableRadioButton1);
mrbDinnerTypeEvening = findViewById(R.id.activityprenulldiningtableRadioButton2);
mrbDinnerTypeEvening.setChecked(true);
}
//
// @Override
// protected Toolbar initToolBar() {
// return findViewById(R.id.activityprenulldiningtableToolbar1);
// }
//
// @Override
// protected boolean isAddWinBoLLToolBar() {
// return false;
// }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
WinBoLLActivityManager.getInstance().finish(this);
}
return super.onOptionsItemSelected(item);
}
void addTable() {
mListTableInfo.add(new DiningTableBean("201", 18, false));
mListTableInfo.add(new DiningTableBean("202", 8, false));
mListTableInfo.add(new DiningTableBean("203", 8, false));
mListTableInfo.add(new DiningTableBean("205", 10, false));
mListTableInfo.add(new DiningTableBean("206", 0, false));
mListTableInfo.add(new DiningTableBean("207", 0, false));
mListTableInfo.add(new DiningTableBean("208", 8, false));
mListTableInfo.add(new DiningTableBean("209", 10, false));
mListTableInfo.add(new DiningTableBean("210", 8, false));
mListTableInfo.add(new DiningTableBean("211", 12, false));
mListTableInfo.add(new DiningTableBean("212", 8, false));
mListTableInfo.add(new DiningTableBean("213", 9, false));
mListTableInfo.add(new DiningTableBean("666", 14, false));
mListTableInfo.add(new DiningTableBean("888", 20, false));
}
public void onDinnerType(View view) {
RadioButton rb = (RadioButton)view;
if (rb.getId() == mrbDinnerTypeNoon.getId()) {
ToastUtils.show("午餐");
mrbDinnerTypeEvening.setChecked(false);
} else {
ToastUtils.show("晚餐");
mrbDinnerTypeNoon.setChecked(false);
}
}
public void onCopyResultText(View view) {
// Gets a handle to the clipboard service.
ClipboardManager clipboard = (ClipboardManager) getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE);
// Creates a new text clip to put on the clipboard
ClipData clip = ClipData.newPlainText("simple text", metPreBookList.getText());
// Set the clipboard's primary clip.
clipboard.setPrimaryClip(clip);
Toast.makeText(getApplicationContext(), "Copy to clipboard.", Toast.LENGTH_SHORT).show();
}
public void onCleanResultText(View view) {
metPreBookList.setText("");
}
public void onCreatePreBookList(View view) {
String szDinnerTyp = mrbDinnerTypeEvening.isChecked() ?"": "";
EditText etDate = findViewById(R.id.activityprenulldiningtableEditText1);
StringBuilder sbPreBookList = new StringBuilder();
for (DiningTableBean item : mListTableInfo) {
if (item.getIsSelected()) {
/*sbPreBookList.append(etDate.getText());
sbPreBookList.append("号 ");
sbPreBookList.append(szDinnerTyp);
sbPreBookList.append(" ");
sbPreBookList.append(item.getTableNumber());
sbPreBookList.append("房-\n");*/
String szTableType = "";
if (item.getTableType() == DiningTableBean.TableType.Room) {
szTableType = "";
}
if (item.getTableType() == DiningTableBean.TableType.Table) {
szTableType = "";
}
sbPreBookList.append(etDate.getText());
sbPreBookList.append("");
sbPreBookList.append(szDinnerTyp);
sbPreBookList.append(" ");
sbPreBookList.append(item.getTableNumber());
sbPreBookList.append(szTableType);
sbPreBookList.append("-");
sbPreBookList.append(item.getBookDesc());
sbPreBookList.append("\n");
}
}
//metPreBookList.append("\n");
metPreBookList.append(sbPreBookList.toString());
mScrollView.post(new Runnable() {
@Override
public void run() {
mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
}
public void onSelectALLTable(View view) {
boolean isSelectAll =((CheckBox)findViewById(R.id.activityprenulldiningtableCheckBox1)).isChecked();
for (DiningTableBean item : mListTableInfo) {
item.setIsSelected(isSelectAll);
}
//ToastUtils.show(Boolean.toString(isSelectAll));
mDiningTableBeanListAdapter.notifyDataSetChanged();
}
class DiningTableBeanListAdapter extends RecyclerView.Adapter {
ArrayList<DiningTableBean> mDataList;
public DiningTableBeanListAdapter(ArrayList<DiningTableBean> listInfo) {
mDataList = listInfo;
}
@Override
public int getItemCount() {
return mDataList.size();
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final DiningTableBean item = mDataList.get(position);
if (holder.getItemViewType() == 0) {
final SimpleViewHolder viewHolder = (SimpleViewHolder) holder;
viewHolder.mcbTable.setText(item.getTableNumber() + "房(" + Integer.toString(item.getMaxPersonCount()) + "人)");
viewHolder.mcbTable.setChecked(item.getIsSelected());
viewHolder.mcbTable.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
item.setIsSelected(viewHolder.mcbTable.isChecked());
}
});
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_tableinfo, parent, false);
return new SimpleViewHolder(view);
}
return null;
}
class SimpleViewHolder extends RecyclerView.ViewHolder {
CheckBox mcbTable;
SimpleViewHolder(View itemView) {
super(itemView);
mcbTable = itemView.findViewById(R.id.listviewtableinfoCheckBox1);
}
}
}
}
@@ -0,0 +1,693 @@
package cc.winboll.studio.stallhelper.activities;
import android.app.Dialog;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.stallhelper.R;
import cc.winboll.studio.stallhelper.beans.TaskSchedulerBean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/**
* @Author ZhanGSKen
* @Date 2026/05/18
* @Describe 任务排档窗口
*/
public class TaskSchedulerActivity extends WinBoLLActivity {
public static final String TAG = "TaskSchedulerActivity";
// 时间转换常量
private static final int MINUTES_PER_HOUR = 60;
private static final int HOURS_PER_DAY = 24;
private static final int DAYS_PER_MONTH = 30; // 默认按30天计算
ArrayList<TaskSchedulerBean> mTaskList;
TaskSchedulerAdapter mAdapter;
@Override
public String getTag() {
return TAG;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_task_scheduler);
LogUtils.i(TAG, "onCreate: 任务排档页面初始化");
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
setTitle("任务排档");
// 初始化任务列表
mTaskList = new ArrayList<TaskSchedulerBean>();
loadTaskData();
// 设置 RecyclerView
RecyclerView recyclerView = findViewById(R.id.task_scheduler_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false));
mAdapter = new TaskSchedulerAdapter(mTaskList);
recyclerView.setAdapter(mAdapter);
// 设置悬浮按钮点击事件
Button fabAddTask = findViewById(R.id.fab_add_task);
fabAddTask.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showAddTaskDialog();
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
WinBoLLActivityManager.getInstance().finish(this);
}
return super.onOptionsItemSelected(item);
}
/**
* 从文件加载任务数据
*/
private void loadTaskData() {
boolean loadSuccess = TaskSchedulerBean.loadBeanList(this, mTaskList, TaskSchedulerBean.class);
if (loadSuccess) {
LogUtils.i(TAG, "loadTaskData: 成功加载 " + mTaskList.size() + " 条任务数据");
} else {
LogUtils.i(TAG, "loadTaskData: 未找到已保存的任务数据,使用空列表");
}
sortTaskList();
}
/**
* 保存任务数据到文件
*/
private void saveTaskData() {
boolean saveSuccess = TaskSchedulerBean.saveBeanList(this, mTaskList, TaskSchedulerBean.class);
if (saveSuccess) {
LogUtils.i(TAG, "saveTaskData: 成功保存 " + mTaskList.size() + " 条任务数据");
} else {
LogUtils.e(TAG, "saveTaskData: 任务数据保存失败");
}
}
/**
* 按排档时间倒序排列列表
*/
private void sortTaskList() {
Collections.sort(mTaskList, new Comparator<TaskSchedulerBean>() {
@Override
public int compare(TaskSchedulerBean a, TaskSchedulerBean b) {
long diff = a.getCurrentScheduleTime() - b.getCurrentScheduleTime();
if (diff > 0) return 1;
if (diff < 0) return -1;
return 0;
}
});
}
/**
* 格式化时间戳为年月日和小时
* @param timestamp 时间戳
* @return 格式化的时间字符串,如 "2026-05-18 09"
*/
private String formatTimestamp(long timestamp) {
if (timestamp == 0) {
return "";
}
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH");
java.util.Date date = new java.util.Date(timestamp);
return sdf.format(date);
}
/**
* 解析时间字符串为时间戳
* @param timeStr 时间字符串,如 "2026-05-18 09"
* @return 时间戳
*/
private long parseTimeString(String timeStr) {
if (timeStr == null || timeStr.trim().isEmpty()) {
return 0;
}
try {
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH");
java.util.Date date = sdf.parse(timeStr);
return date.getTime();
} catch (Exception e) {
LogUtils.e(TAG, "parseTimeString: 时间解析错误", e);
return 0;
}
}
/**
* 初始化示例数据
*/
private void initSampleData() {
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.set(java.util.Calendar.MINUTE, 0);
calendar.set(java.util.Calendar.SECOND, 0);
calendar.set(java.util.Calendar.MILLISECOND, 0);
calendar.set(java.util.Calendar.HOUR_OF_DAY, 9);
long time9 = calendar.getTimeInMillis();
calendar.set(java.util.Calendar.HOUR_OF_DAY, 10);
long time10 = calendar.getTimeInMillis();
calendar.set(java.util.Calendar.HOUR_OF_DAY, 11);
calendar.set(java.util.Calendar.MINUTE, 30);
long time1130 = calendar.getTimeInMillis();
calendar.set(java.util.Calendar.HOUR_OF_DAY, 12);
calendar.set(java.util.Calendar.MINUTE, 30);
long time1230 = calendar.getTimeInMillis();
calendar.set(java.util.Calendar.HOUR_OF_DAY, 16);
calendar.set(java.util.Calendar.MINUTE, 0);
long time16 = calendar.getTimeInMillis();
calendar.set(java.util.Calendar.HOUR_OF_DAY, 17);
long time17 = calendar.getTimeInMillis();
mTaskList.add(new TaskSchedulerBean("准备食材", "购买新鲜蔬菜和肉类", time9, 60));
mTaskList.add(new TaskSchedulerBean("烹饪午餐", "按照食谱准备午餐", time10, 90));
mTaskList.add(new TaskSchedulerBean("用餐休息", "享受美食并休息", time1130, 60));
mTaskList.add(new TaskSchedulerBean("清洁厨房", "清洗餐具和整理厨房", time1230, 45));
mTaskList.add(new TaskSchedulerBean("准备晚餐", "提前准备晚餐食材", time16, 60));
mTaskList.add(new TaskSchedulerBean("烹饪晚餐", "制作丰盛的晚餐", time17, 90));
}
/**
* 将月、天、小时转换为总分钟数
* @param month 月份
* @param day 天数
* @param hour 小时
* @return 总分钟数
*/
private int convertToTotalMinutes(int month, int day, int hour) {
return month * DAYS_PER_MONTH * HOURS_PER_DAY * MINUTES_PER_HOUR +
day * HOURS_PER_DAY * MINUTES_PER_HOUR +
hour * MINUTES_PER_HOUR;
}
/**
* 将总分钟数转换为月、天、小时的格式字符串
* @param totalMinutes 总分钟数
* @return 格式化的字符串,如 "0月0天1小时"
*/
private String formatDurationToString(int totalMinutes) {
int totalHours = totalMinutes / MINUTES_PER_HOUR;
int totalDays = totalHours / HOURS_PER_DAY;
int month = totalDays / DAYS_PER_MONTH;
int day = totalDays % DAYS_PER_MONTH;
int hour = totalHours % HOURS_PER_DAY;
StringBuilder sb = new StringBuilder();
if (month > 0) {
sb.append(month).append("");
}
if (day > 0) {
sb.append(day).append("");
}
if (hour > 0) {
sb.append(hour).append("小时");
}
if (sb.length() == 0) {
sb.append("0小时");
}
return sb.toString();
}
/**
* 显示编辑任务对话框
* @param position 要编辑的任务位置
*/
private void showEditTaskDialog(final int position) {
if (position < 0 || position >= mTaskList.size()) {
return;
}
final TaskSchedulerBean task = mTaskList.get(position);
final Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_task_edit);
final EditText etTaskName = dialog.findViewById(R.id.dialog_et_task_name);
final EditText etCurrentScheduleTime = dialog.findViewById(R.id.dialog_et_start_time);
final EditText etMonth = dialog.findViewById(R.id.dialog_et_month);
final EditText etDay = dialog.findViewById(R.id.dialog_et_day);
final EditText etHour = dialog.findViewById(R.id.dialog_et_hour);
final EditText etRemark = dialog.findViewById(R.id.dialog_et_remark);
Button btnCancel = dialog.findViewById(R.id.dialog_btn_cancel);
Button btnSave = dialog.findViewById(R.id.dialog_btn_save);
Button btnNow = dialog.findViewById(R.id.dialog_btn_now);
etTaskName.setText(task.getTaskName());
etCurrentScheduleTime.setText(formatTimestamp(task.getCurrentScheduleTime()));
etRemark.setText(task.getRemark());
int totalMinutes = task.getDurationMinutes();
int totalHours = totalMinutes / MINUTES_PER_HOUR;
int totalDays = totalHours / HOURS_PER_DAY;
int month = totalDays / DAYS_PER_MONTH;
int day = totalDays % DAYS_PER_MONTH;
int hour = totalHours % HOURS_PER_DAY;
if (month > 0) {
etMonth.setText(Integer.toString(month));
}
if (day > 0) {
etDay.setText(Integer.toString(day));
}
if (hour > 0) {
etHour.setText(Integer.toString(hour));
}
btnNow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.set(java.util.Calendar.MINUTE, 0);
calendar.set(java.util.Calendar.SECOND, 0);
calendar.set(java.util.Calendar.MILLISECOND, 0);
etCurrentScheduleTime.setText(formatTimestamp(calendar.getTimeInMillis()));
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String taskName = etTaskName.getText().toString().trim();
String currentScheduleTime = etCurrentScheduleTime.getText().toString().trim();
String monthStr = etMonth.getText().toString().trim();
String dayStr = etDay.getText().toString().trim();
String hourStr = etHour.getText().toString().trim();
String remark = etRemark.getText().toString().trim();
if (taskName.isEmpty()) {
etTaskName.setError("请输入任务名称");
return;
}
if (currentScheduleTime.isEmpty()) {
etCurrentScheduleTime.setError("请输入当前排档时间");
return;
}
long timestamp = parseTimeString(currentScheduleTime);
if (timestamp == 0) {
etCurrentScheduleTime.setError("时间格式不正确,请使用 yyyy-MM-dd HH 格式");
return;
}
int month = 0, day = 0, hour = 0;
try {
if (!monthStr.isEmpty()) month = Integer.parseInt(monthStr);
if (!dayStr.isEmpty()) day = Integer.parseInt(dayStr);
if (!hourStr.isEmpty()) hour = Integer.parseInt(hourStr);
} catch (NumberFormatException e) {
LogUtils.e(TAG, "showEditTaskDialog: 数字解析错误", e);
return;
}
int durationMinutes = convertToTotalMinutes(month, day, hour);
task.setTaskName(taskName);
task.setCurrentScheduleTime(timestamp);
task.setDurationMinutes(durationMinutes);
task.setRemark(remark);
sortTaskList();
mAdapter.notifyDataSetChanged();
saveTaskData();
LogUtils.i(TAG, "showEditTaskDialog: 任务 [" + taskName + "] 数据已更新,排档幅度=" + durationMinutes + "分钟");
dialog.dismiss();
}
});
dialog.show();
}
/**
* 显示添加任务对话框
*/
private void showAddTaskDialog() {
final Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_task_edit);
final EditText etTaskName = dialog.findViewById(R.id.dialog_et_task_name);
final EditText etCurrentScheduleTime = dialog.findViewById(R.id.dialog_et_start_time);
final EditText etMonth = dialog.findViewById(R.id.dialog_et_month);
final EditText etDay = dialog.findViewById(R.id.dialog_et_day);
final EditText etHour = dialog.findViewById(R.id.dialog_et_hour);
final EditText etRemark = dialog.findViewById(R.id.dialog_et_remark);
Button btnCancel = dialog.findViewById(R.id.dialog_btn_cancel);
Button btnSave = dialog.findViewById(R.id.dialog_btn_save);
Button btnNow = dialog.findViewById(R.id.dialog_btn_now);
// 设置默认时间为当前时间
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.set(java.util.Calendar.MINUTE, 0);
calendar.set(java.util.Calendar.SECOND, 0);
calendar.set(java.util.Calendar.MILLISECOND, 0);
etCurrentScheduleTime.setText(formatTimestamp(calendar.getTimeInMillis()));
btnNow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
java.util.Calendar cal = java.util.Calendar.getInstance();
cal.set(java.util.Calendar.MINUTE, 0);
cal.set(java.util.Calendar.SECOND, 0);
cal.set(java.util.Calendar.MILLISECOND, 0);
etCurrentScheduleTime.setText(formatTimestamp(cal.getTimeInMillis()));
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String taskName = etTaskName.getText().toString().trim();
String currentScheduleTime = etCurrentScheduleTime.getText().toString().trim();
String monthStr = etMonth.getText().toString().trim();
String dayStr = etDay.getText().toString().trim();
String hourStr = etHour.getText().toString().trim();
String remark = etRemark.getText().toString().trim();
if (taskName.isEmpty()) {
etTaskName.setError("请输入任务名称");
return;
}
if (currentScheduleTime.isEmpty()) {
etCurrentScheduleTime.setError("请输入当前排档时间");
return;
}
long timestamp = parseTimeString(currentScheduleTime);
if (timestamp == 0) {
etCurrentScheduleTime.setError("时间格式不正确,请使用 yyyy-MM-dd HH 格式");
return;
}
int month = 0, day = 0, hour = 0;
try {
if (!monthStr.isEmpty()) month = Integer.parseInt(monthStr);
if (!dayStr.isEmpty()) day = Integer.parseInt(dayStr);
if (!hourStr.isEmpty()) hour = Integer.parseInt(hourStr);
} catch (NumberFormatException e) {
LogUtils.e(TAG, "showAddTaskDialog: 数字解析错误", e);
return;
}
int durationMinutes = convertToTotalMinutes(month, day, hour);
TaskSchedulerBean newTask = new TaskSchedulerBean(taskName, remark, timestamp, durationMinutes);
mTaskList.add(newTask);
sortTaskList();
mAdapter.notifyDataSetChanged();
saveTaskData();
LogUtils.i(TAG, "showAddTaskDialog: 任务 [" + taskName + "] 已添加,排档幅度=" + durationMinutes + "分钟");
dialog.dismiss();
}
});
dialog.show();
}
/**
* 显示删除确认对话框
* @param position 要删除的任务位置
*/
private void showDeleteConfirmDialog(final int position) {
if (position < 0 || position >= mTaskList.size()) {
return;
}
final TaskSchedulerBean task = mTaskList.get(position);
final Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_task_edit);
// 修改对话框布局,只保留必要的按钮
// 隐藏不需要的视图
android.view.View etTaskName = dialog.findViewById(R.id.dialog_et_task_name);
android.view.View etCurrentScheduleTime = dialog.findViewById(R.id.dialog_et_start_time);
android.view.View etMonth = dialog.findViewById(R.id.dialog_et_month);
android.view.View etDay = dialog.findViewById(R.id.dialog_et_day);
android.view.View etHour = dialog.findViewById(R.id.dialog_et_hour);
android.view.View etRemark = dialog.findViewById(R.id.dialog_et_remark);
if (etTaskName != null) etTaskName.setVisibility(View.GONE);
if (etCurrentScheduleTime != null) etCurrentScheduleTime.setVisibility(View.GONE);
if (etMonth != null) etMonth.setVisibility(View.GONE);
if (etDay != null) etDay.setVisibility(View.GONE);
if (etHour != null) etHour.setVisibility(View.GONE);
if (etRemark != null) etRemark.setVisibility(View.GONE);
// 添加提示文本
android.widget.TextView tvMessage = new android.widget.TextView(this);
tvMessage.setText("确定要删除任务 \"" + task.getTaskName() + "\" 吗?");
tvMessage.setPadding(40, 40, 40, 20);
tvMessage.setTextSize(16);
android.view.ViewGroup rootView = dialog.findViewById(android.R.id.content);
if (rootView != null) {
android.view.ViewGroup.LayoutParams params = new android.view.ViewGroup.LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.WRAP_CONTENT
);
rootView.addView(tvMessage, 0, params);
}
Button btnCancel = dialog.findViewById(R.id.dialog_btn_cancel);
Button btnSave = dialog.findViewById(R.id.dialog_btn_save);
if (btnSave != null) {
btnSave.setText("确定删除");
}
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String taskName = task.getTaskName();
mTaskList.remove(position);
sortTaskList();
mAdapter.notifyDataSetChanged();
saveTaskData();
LogUtils.i(TAG, "showDeleteConfirmDialog: 任务 [" + taskName + "] 已删除");
dialog.dismiss();
}
});
dialog.show();
}
/**
* 显示排档确认对话框
* @param position 要排档的任务位置
*/
private void showScheduleConfirmDialog(final int position) {
if (position < 0 || position >= mTaskList.size()) {
return;
}
final TaskSchedulerBean task = mTaskList.get(position);
long currentTime = task.getCurrentScheduleTime();
int duration = task.getDurationMinutes();
long newTime = currentTime + duration * 60 * 1000L;
final Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_schedule_confirm);
TextView tvTaskName = dialog.findViewById(R.id.dialog_schedule_task_name);
TextView tvCurrentTime = dialog.findViewById(R.id.dialog_schedule_current_time);
TextView tvDuration = dialog.findViewById(R.id.dialog_schedule_duration);
TextView tvRemark = dialog.findViewById(R.id.dialog_schedule_remark);
TextView tvNewTime = dialog.findViewById(R.id.dialog_schedule_new_time);
Button btnCancel = dialog.findViewById(R.id.dialog_btn_cancel);
Button btnConfirm = dialog.findViewById(R.id.dialog_btn_confirm);
tvTaskName.setText("任务:" + task.getTaskName());
tvCurrentTime.setText("当前排档时间:" + formatTimestamp(currentTime));
tvDuration.setText("排档幅度:" + formatDurationToString(duration));
tvRemark.setText("备注:" + (task.getRemark() != null && !task.getRemark().isEmpty() ? task.getRemark() : ""));
tvNewTime.setText("排档后时间:" + formatTimestamp(newTime));
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
btnConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
performSchedule(position);
}
});
dialog.show();
}
/**
* 执行排档操作
* @param position 点击排档按钮的任务位置
*/
private void performSchedule(int position) {
if (position < 0 || position >= mTaskList.size()) {
return;
}
TaskSchedulerBean currentTask = mTaskList.get(position);
long currentTime = currentTask.getCurrentScheduleTime();
int duration = currentTask.getDurationMinutes();
long newTime = currentTime + duration * 60 * 1000L;
LogUtils.i(TAG, "performSchedule: 当前时间 " + formatTimestamp(currentTime) + " + " + duration + "分钟 = " + formatTimestamp(newTime));
currentTask.setCurrentScheduleTime(newTime);
sortTaskList();
mAdapter.notifyDataSetChanged();
saveTaskData();
LogUtils.i(TAG, "performSchedule: 更新任务 [" + currentTask.getTaskName() + "] 时间更新为 " + formatTimestamp(newTime));
}
/**
* RecyclerView 适配器
*/
class TaskSchedulerAdapter extends RecyclerView.Adapter {
ArrayList<TaskSchedulerBean> mDataList;
public TaskSchedulerAdapter(ArrayList<TaskSchedulerBean> dataList) {
mDataList = dataList;
}
@Override
public int getItemCount() {
return mDataList.size();
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final TaskSchedulerBean item = mDataList.get(position);
final TaskViewHolder viewHolder = (TaskViewHolder) holder;
viewHolder.mtvTaskName.setText(item.getTaskName());
viewHolder.mtvCurrentScheduleTime.setText(formatTimestamp(item.getCurrentScheduleTime()));
viewHolder.mtvDuration.setText(formatDurationToString(item.getDurationMinutes()));
viewHolder.mtvRemark.setText(item.getRemark());
long diffMs = item.getCurrentScheduleTime() - System.currentTimeMillis();
int diffMinutes = (int) Math.abs(diffMs / 60000);
if (diffMs >= 0) {
viewHolder.mtvTimeDiff.setText("剩余" + formatDurationToString(diffMinutes));
} else {
viewHolder.mtvTimeDiff.setText("已过" + formatDurationToString(diffMinutes));
}
if (item.getCurrentScheduleTime() <= System.currentTimeMillis()) {
viewHolder.mllMain.setBackgroundResource(R.color.colorScheduleFutureBackground);
} else {
viewHolder.mllMain.setBackgroundResource(R.drawable.bg_frame);
}
// 长按直接内置菜单,直接使用当前position
viewHolder.mllMain.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(final View v) {
// 使用PopupMenu替代ContextMenu
PopupMenu popup = new PopupMenu(TaskSchedulerActivity.this, v);
popup.getMenu().add("编辑任务内容");
popup.getMenu().add("删除任务");
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
String title = item.getTitle().toString();
if ("编辑任务内容".equals(title)) {
showEditTaskDialog(position);
return true;
} else if ("删除任务".equals(title)) {
showDeleteConfirmDialog(position);
return true;
}
return false;
}
});
// 弹出菜单
popup.show();
return true;
}
});
viewHolder.mbtnSchedule.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showScheduleConfirmDialog(position);
}
});
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_task_scheduler, parent, false);
return new TaskViewHolder(view);
}
class TaskViewHolder extends RecyclerView.ViewHolder {
TextView mtvTaskName;
TextView mtvCurrentScheduleTime;
TextView mtvTimeDiff;
TextView mtvDuration;
TextView mtvRemark;
LinearLayout mllMain;
Button mbtnSchedule;
TaskViewHolder(View itemView) {
super(itemView);
mtvTaskName = itemView.findViewById(R.id.item_task_name);
mtvCurrentScheduleTime = itemView.findViewById(R.id.item_start_time);
mtvTimeDiff = itemView.findViewById(R.id.item_time_diff);
mtvDuration = itemView.findViewById(R.id.item_duration);
mtvRemark = itemView.findViewById(R.id.item_remark);
mllMain = itemView.findViewById(R.id.itemtaskscheduler_llmain);
mbtnSchedule = itemView.findViewById(R.id.item_btn_schedule);
}
}
}
}
@@ -0,0 +1,82 @@
package cc.winboll.studio.stallhelper.activities;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/28 15:34:16
* @Describe 应用活动窗口基类
*/
import android.app.Activity;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.stallhelper.App;
import cc.winboll.studio.stallhelper.R;
public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivity {
public static final String TAG = "WinBoLLActivityBase";
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
WinBoLLActivityManager getWinBoLLActivityManager() {
return WinBoLLActivityManager.getInstance();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWinBoLLActivityManager().add(this);
}
@Override
public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) {
// GlobalApplication.getWinBoLLActivityManager().startLogActivity(this);
// return true;
// } else if(item.getItemId() == cc.winboll.studio.appbase.R.id.item_minimal) {
// //moveTaskToBack(true);
// exit();
// }
// 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。
return super.onOptionsItemSelected(item);
}
void exit() {
YesNoAlertDialog.show(this, "Exit " + getString(R.string.app_name), "Close all activity and exit?", new YesNoAlertDialog.OnDialogResultListener(){
@Override
public void onYes() {
WinBoLLActivityManager.getInstance().finishAll();
}
@Override
public void onNo() {
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
getWinBoLLActivityManager().registeRemove(this);
}
}
@@ -0,0 +1,216 @@
package cc.winboll.studio.stallhelper.beans;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/10/16 06:09:54
* @Describe 餐桌
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class DiningTableBean extends BaseBean {
public static final String TAG = "AuthenticationBean";
public enum DinnerType { Noon, Evening };
public enum TableType { Room, Table };
// 餐桌号
String tableNumber;
// 最大就餐人数
int maxPersonCount;
// 是否选取了这张桌号
boolean isSelected;
// 预定时间类型
DinnerType dinnerType;
// 预定信息
String bookDesc;
// 预定时间
String date;
// 餐桌类型
TableType tableType;
// 是否被识别为 DiningTableBean
boolean isDiningTableBean;
// 或者是无法识别为 DiningTableBean 的原始信息。
String originDesc;
public DiningTableBean(String tableNumber, int maxPersonCount, boolean isSelected) {
this.tableNumber = tableNumber;
this.maxPersonCount = maxPersonCount;
this.isSelected = isSelected;
this.dinnerType = DinnerType.Evening;
this.bookDesc = "";
this.date = "";
this.tableType = TableType.Room;
this.isDiningTableBean = true;
this.originDesc = "";
}
public DiningTableBean(String tableNumber, int maxPersonCount, boolean isSelected, String date) {
this.tableNumber = tableNumber;
this.maxPersonCount = maxPersonCount;
this.isSelected = isSelected;
this.dinnerType = DinnerType.Evening;
this.bookDesc = "";
this.date = date;
this.tableType = TableType.Room;
this.isDiningTableBean = true;
this.originDesc = "";
}
public DiningTableBean(String tableNumber, int maxPersonCount, boolean isSelected, DinnerType dinnerType, String bookDesc, String date, TableType tableType) {
this.tableNumber = tableNumber;
this.maxPersonCount = maxPersonCount;
this.isSelected = isSelected;
this.dinnerType = dinnerType;
this.bookDesc = bookDesc;
this.date = date;
this.tableType = tableType;
this.isDiningTableBean = true;
this.originDesc = "";
}
public DiningTableBean(boolean isSelected, boolean isDiningTableBean, String originDesc) {
this.tableNumber = "";
this.maxPersonCount = 0;
this.isSelected = isSelected;
this.dinnerType = DinnerType.Evening;
this.bookDesc = "";
this.date = "";
this.tableType = TableType.Room;
this.isDiningTableBean = isDiningTableBean;
this.originDesc = originDesc;
}
public void setOriginDesc(String originDesc) {
this.originDesc = originDesc;
}
public String getOriginDesc() {
return originDesc;
}
public void setIsDiningTableBean(boolean isDiningTableBean) {
this.isDiningTableBean = isDiningTableBean;
}
public boolean isDiningTableBean() {
return isDiningTableBean;
}
public void setTableType(TableType tableType) {
this.tableType = tableType;
}
public TableType getTableType() {
return tableType;
}
public void setDate(String date) {
this.date = date;
}
public String getDate() {
return date;
}
public void setDinnerType(DinnerType dinnerType) {
this.dinnerType = dinnerType;
}
public DinnerType getDinnerType() {
return dinnerType;
}
public void setBookDesc(String bookDesc) {
this.bookDesc = bookDesc;
}
public String getBookDesc() {
return bookDesc;
}
public void setIsSelected(boolean isSelected) {
this.isSelected = isSelected;
}
public boolean getIsSelected() {
return isSelected;
}
public void setTableNumber(String tableNumber) {
this.tableNumber = tableNumber;
}
public String getTableNumber() {
return tableNumber;
}
public void setMaxPersonCount(int maxPersonCount) {
this.maxPersonCount = maxPersonCount;
}
public int getMaxPersonCount() {
return maxPersonCount;
}
@Override
public String getName() {
return DiningTableBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
DiningTableBean bean = this;
jsonWriter.name("tableNumber").value(bean.getTableNumber());
jsonWriter.name("maxPersonCount").value(bean.getMaxPersonCount());
jsonWriter.name("isSelected").value(bean.getTableNumber());
jsonWriter.name("dinnerType").value(bean.getDinnerType().ordinal());
jsonWriter.name("bookDesc").value(bean.getBookDesc());
jsonWriter.name("date").value(bean.getDate());
jsonWriter.name("tableType").value(bean.getTableType().ordinal());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("tableNumber")) {
setTableNumber(jsonReader.nextString());
} else if (name.equals("maxPersonCount")) {
setMaxPersonCount(jsonReader.nextInt());
} else if (name.equals("isSelected")) {
setIsSelected(jsonReader.nextBoolean());
} else if (name.equals("dinnerType")) {
setDinnerType(DinnerType.values()[jsonReader.nextInt()]);
} else if (name.equals("bookDesc")) {
setBookDesc(jsonReader.nextString());
} else if (name.equals("date")) {
setDate(jsonReader.nextString());
} else if (name.equals("tableType")) {
setTableType(TableType.values()[jsonReader.nextInt()]);
} else {
return false;
}
}
return true;
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, name)) {
jsonReader.skipValue();
}
}
// 结束 JSON 对象
jsonReader.endObject();
return this;
}
}
@@ -0,0 +1,117 @@
package cc.winboll.studio.stallhelper.beans;
/**
* @Author ZhanGSKen
* @Date 2026/05/18
* @Describe 任务排档数据模型
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class TaskSchedulerBean extends BaseBean {
public static final String TAG = "TaskSchedulerBean";
// 任务排档名称
String taskName;
// 备注
String remark;
// 当前排档时间(时间戳)
long currentScheduleTime;
// 排档时间幅度(分钟)- 用于计算下一个任务的起始时间
int durationMinutes;
public TaskSchedulerBean() {
this.taskName = "";
this.remark = "";
this.currentScheduleTime = 0;
this.durationMinutes = 0;
}
public TaskSchedulerBean(String taskName, String remark, long currentScheduleTime, int durationMinutes) {
this.taskName = taskName;
this.remark = remark;
this.currentScheduleTime = currentScheduleTime;
this.durationMinutes = durationMinutes;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public long getCurrentScheduleTime() {
return currentScheduleTime;
}
public void setCurrentScheduleTime(long currentScheduleTime) {
this.currentScheduleTime = currentScheduleTime;
}
public int getDurationMinutes() {
return durationMinutes;
}
public void setDurationMinutes(int durationMinutes) {
this.durationMinutes = durationMinutes;
}
@Override
public String getName() {
return TaskSchedulerBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
TaskSchedulerBean bean = this;
jsonWriter.name("taskName").value(bean.getTaskName());
jsonWriter.name("remark").value(bean.getRemark());
jsonWriter.name("startTime").value(bean.getCurrentScheduleTime());
jsonWriter.name("durationMinutes").value(bean.getDurationMinutes());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("taskName")) {
setTaskName(jsonReader.nextString());
} else if (name.equals("remark")) {
setRemark(jsonReader.nextString());
} else if (name.equals("startTime")) {
setCurrentScheduleTime(jsonReader.nextLong());
} else if (name.equals("durationMinutes")) {
setDurationMinutes(jsonReader.nextInt());
} else {
return false;
}
}
return true;
}
@Override
public TaskSchedulerBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, name)) {
jsonReader.skipValue();
}
}
jsonReader.endObject();
return this;
}
}
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 阴影部分 -->
<!-- 个人觉得更形象的表达:top代表下边的阴影高度,left代表右边的阴影宽度。其实也就是相对应的offset,solid中的颜色是阴影的颜色,也可以设置角度等等 -->
<item
android:left="2dp"
android:top="2dp"
android:right="2dp"
android:bottom="2dp">
<shape android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#0F000000"
android:startColor="#0F000000" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>
</item>
<!-- 背景部分 -->
<!-- 形象的表达:bottom代表背景部分在上边缘超出阴影的高度,right代表背景部分在左边超出阴影的宽度(相对应的offset) -->
<item
android:left="3dp"
android:top="3dp"
android:right="3dp"
android:bottom="5dp">
<shape android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#0FFFFFFF"
android:startColor="#FFFFFFFF" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 阴影部分 -->
<!-- 个人觉得更形象的表达:top代表下边的阴影高度,left代表右边的阴影宽度。其实也就是相对应的offset,solid中的颜色是阴影的颜色,也可以设置角度等等 -->
<item
android:left="2dp"
android:top="2dp"
android:right="2dp"
android:bottom="2dp">
<shape android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#0F000000"
android:startColor="#0F000000" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>
</item>
<!-- 背景部分 -->
<!-- 形象的表达:bottom代表背景部分在上边缘超出阴影的高度,right代表背景部分在左边超出阴影的宽度(相对应的offset) -->
<item
android:left="3dp"
android:top="3dp"
android:right="3dp"
android:bottom="5dp">
<shape android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#AF000000"
android:startColor="#AF000000" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 阴影部分 -->
<!-- 个人觉得更形象的表达:top代表下边的阴影高度,left代表右边的阴影宽度。其实也就是相对应的offset,solid中的颜色是阴影的颜色,也可以设置角度等等 -->
<item
android:left="2dp"
android:top="2dp"
android:right="2dp"
android:bottom="2dp">
<shape android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#0FFFFFFF"
android:startColor="#0FFFFFFF" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>
</item>
<!-- 背景部分 -->
<!-- 形象的表达:bottom代表背景部分在上边缘超出阴影的高度,right代表背景部分在左边超出阴影的宽度(相对应的offset) -->
<item
android:left="3dp"
android:top="3dp"
android:right="3dp"
android:bottom="5dp">
<shape android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#CFFFFFFF"
android:startColor="#CFFFFFFF" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,69 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M67.56 132.48C67.56 132.48 196.61 132.48 196.61 132.48 196.61 132.48 196.61 140.79 196.61 140.79 196.61 140.79 67.56 140.79 67.56 140.79 67.56 140.79 67.56 132.48 67.56 132.48"/>
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M100.51 140.79C100.51 140.79 108.38 140.79 108.38 140.79 108.38 140.79 108.38 211.22 108.38 211.22 108.38 211.22 100.51 211.22 100.51 211.22 100.51 211.22 100.51 140.79 100.51 140.79"/>
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M157.4 140.79C157.4 140.79 165.72 140.79 165.72 140.79 165.72 140.79 165.72 211.22 165.72 211.22 165.72 211.22 157.4 211.22 157.4 211.22 157.4 211.22 157.4 140.79 157.4 140.79"/>
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M32.05 85.46C32.05 85.46 38.61 85.46 38.61 85.46 38.61 85.46 38.61 211.22 38.61 211.22 38.61 211.22 32.05 211.22 32.05 211.22 32.05 211.22 32.05 85.46 32.05 85.46"/>
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M38.61 160.26C38.61 160.26 77.24 160.26 77.24 160.26 77.24 160.26 77.24 165.51 77.24 165.51 77.24 165.51 38.61 165.51 38.61 165.51 38.61 165.51 38.61 160.26 38.61 160.26"/>
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M73.52 160.26C73.52 160.26 80.96 160.26 80.96 160.26 80.96 160.26 80.96 211.22 80.96 211.22 80.96 211.22 73.52 211.22 73.52 211.22 73.52 211.22 73.52 160.26 73.52 160.26"/>
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M226.71 85.46C226.71 85.46 233.27 85.46 233.27 85.46 233.27 85.46 233.27 211.22 233.27 211.22 233.27 211.22 226.71 211.22 226.71 211.22 226.71 211.22 226.71 85.46 226.71 85.46"/>
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M188.08 157.64C188.08 157.64 226.71 157.64 226.71 157.64 226.71 157.64 226.71 162.89 226.71 162.89 226.71 162.89 188.08 162.89 188.08 162.89 188.08 162.89 188.08 157.64 188.08 157.64"/>
<path
android:fillColor="#FF977A1F"
android:strokeColor="#FF977A1F"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M188.08 157.64C188.08 157.64 195.52 157.64 195.52 157.64 195.52 157.64 195.52 208.59 195.52 208.59 195.52 208.59 188.08 208.59 188.08 208.59 188.08 208.59 188.08 157.64 188.08 157.64"/>
</vector>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:clickable="true">
<item android:drawable="@drawable/ic_launcher_background"/>
<item
android:left="15dp"
android:top="15dp"
android:right="15dp"
android:bottom="15dp"
android:drawable="@drawable/ic_launcher_foreground"/>
</layer-list>
@@ -2,169 +2,169 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#26A69A"
android:fillColor="@color/colorPrimary"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/>
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

@@ -0,0 +1,62 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="256"
android:viewportHeight="256">
<!-- 背景圆形 -->
<path
android:fillColor="#FF4CAF50"
android:strokeColor="#FF4CAF50"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M128,44 C81.4,44 44,81.4 44,128 C44,174.6 81.4,212 128,212 C174.6,212 212,174.6 212,128 C212,81.4 174.6,44 128,44 Z"/>
<!-- 文档/列表背景 -->
<path
android:fillColor="#FFFFFFFF"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="2.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M85,80 L171,80 L171,180 L85,180 L85,80 Z"/>
<!-- 列表线1 -->
<path
android:fillColor="#FF333333"
android:strokeColor="#FF333333"
android:strokeWidth="4.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M100,100 L156,100"/>
<!-- 列表线2 -->
<path
android:fillColor="#FF333333"
android:strokeColor="#FF333333"
android:strokeWidth="4.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M100,120 L156,120"/>
<!-- 列表线3 -->
<path
android:fillColor="#FF333333"
android:strokeColor="#FF333333"
android:strokeWidth="4.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M100,140 L156,140"/>
<!-- 勾选标记 -->
<path
android:fillColor="#FF4CAF50"
android:strokeColor="#FF4CAF50"
android:strokeWidth="4.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M95,98 L101,104 L115,90"/>
<!-- 时钟指针暗示 -->
<path
android:fillColor="#FF4CAF50"
android:strokeColor="#FF4CAF50"
android:strokeWidth="4.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M128,150 L128,168 L144,168"/>
</vector>
@@ -4,11 +4,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="?attr/activityBackgroundColor">
<cc.winboll.studio.libaes.views.ASupportToolbar
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/toolbarBackgroundColor"
android:id="@+id/toolbar"/>
<cc.winboll.studio.libappbase.views.AboutView
@@ -18,3 +20,4 @@
android:id="@+id/aboutview"/>
</LinearLayout>
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activityBackgroundColor">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/toolbarBackgroundColor"
android:id="@+id/toolbar"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="当前日期:"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/activitycompletediningtableTextView2"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="补全设置:"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<EditText
android:layout_width="wrap_content"
android:ems="10"
android:hint="输入(N或N月N)号"
android:layout_height="wrap_content"
android:id="@+id/activitycompletediningtableEditText3"
android:layout_weight="1.0"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="号晚"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="清空"
android:layout_toLeftOf="@id/activitycompletediningtableButton2"
android:id="@+id/activitycompletediningtableButton3"
android:onClick="onCleanResultText"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="复制"
android:layout_toLeftOf="@id/activitycompletediningtableButton1"
android:id="@+id/activitycompletediningtableButton2"
android:onClick="onCopyResultText"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="补全订餐列表"
android:id="@+id/activitycompletediningtableButton1"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:onClick="onCreatePreBookList"/>
</RelativeLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/activitycompletediningtableScrollView2"
android:layout_weight="1.0">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top"
android:id="@+id/activitycompletediningtableEditText1"/>
</LinearLayout>
</ScrollView>
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="#ccc"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/activitycompletediningtableScrollView1"
android:layout_weight="1.0">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top"
android:id="@+id/activitycompletediningtableEditText2"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activityBackgroundColor">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/toolbarBackgroundColor"
android:id="@+id/toolbar"/>
<LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/bg_frame"
android:onClick="onPreNullDiningTable">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@color/colorPreNullBackgroung"
android:src="@drawable/diningtable"
android:layout_margin="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="餐桌空白预定表制作"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/bg_frame"
android:onClick="onCompleteDiningTable">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@color/colorCompleteBackgroung"
android:src="@drawable/diningtable"
android:layout_margin="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="订餐列表补全"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/bg_frame"
android:onClick="onNoteRecordHelper">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@color/colorCompleteBackgroung"
android:src="@drawable/ic_noterecordhelper"
android:layout_margin="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="订单笔录辅助"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/bg_frame"
android:onClick="onTaskScheduler">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@color/colorPreNullBackgroung"
android:src="@drawable/ic_task_scheduler"
android:layout_margin="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="任务排档"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="?attr/activityBackgroundColor">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/toolbarBackgroundColor"
android:id="@+id/toolbar"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="订单笔录辅助"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center"
android:paddingBottom="16dp"/>
<!-- 输入区域 -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:fillViewport="true">
<EditText
android:id="@+id/et_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="请输入订单内容,每行一条记录"
android:gravity="top|start"
android:background="@android:color/white"
android:textColor="@android:color/black"
android:textSize="18sp"
android:padding="12dp"
android:inputType="textMultiLine|textNoSuggestions"
android:minLines="10"
android:scrollbars="vertical"/>
</ScrollView>
<Button
android:id="@+id/btn_highlight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="一键高亮标记"
android:layout_marginTop="12dp"/>
<!-- 结果区域:关键是 fillViewport -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:layout_marginTop="12dp"
android:fillViewport="true">
<TextView
android:id="@+id/tv_highlight_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:padding="12dp"
android:textSize="18sp"
android:gravity="top|start"
android:scrollbars="vertical"/>
</ScrollView>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activityBackgroundColor">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/toolbarBackgroundColor"
android:id="@+id/toolbar"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="当前日期:"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/activityprenulldiningtableTextView2"/>
</LinearLayout>
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="订餐日期:"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_alignParentLeft="true"
android:id="@+id/activityprenulldiningtableTextView1"
android:layout_centerVertical="true"/>
<EditText
android:layout_width="50dp"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:layout_toRightOf="@+id/activityprenulldiningtableTextView1"
android:id="@+id/activityprenulldiningtableEditText1"
android:layout_centerVertical="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="号"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_toRightOf="@id/activityprenulldiningtableEditText1"
android:layout_centerVertical="true"/>
</RelativeLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="午餐"
android:id="@+id/activityprenulldiningtableRadioButton1"
android:onClick="onDinnerType"/>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="晚餐"
android:id="@+id/activityprenulldiningtableRadioButton2"
android:onClick="onDinnerType"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/activityprenulldiningtableCheckBox1"
android:text="全选"
android:layout_marginRight="10dp"
android:onClick="onSelectALLTable"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_shadow"
android:padding="10dp"
android:id="@+id/activityprenulldiningtableRecyclerView1"/>
</LinearLayout>
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="清空"
android:layout_toLeftOf="@id/activityprenulldiningtableButton2"
android:id="@+id/activityprenulldiningtableButton3"
android:onClick="onCleanResultText"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="复制"
android:layout_toLeftOf="@id/activityprenulldiningtableButton1"
android:id="@+id/activityprenulldiningtableButton2"
android:onClick="onCopyResultText"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="制作订餐列表"
android:id="@+id/activityprenulldiningtableButton1"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:onClick="onCreatePreBookList"/>
</RelativeLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/activityprenulldiningtableScrollView1"
android:layout_weight="1.0">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:id="@+id/activityprenulldiningtableEditText2"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activityBackgroundColor">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/toolbarBackgroundColor"
android:id="@+id/toolbar"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="10dp"
android:id="@+id/task_scheduler_recycler_view"/>
</LinearLayout>
<Button
android:id="@+id/fab_add_task"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:background="@color/colorPrimaryDark"
android:text="+"
android:textColor="@android:color/white"
android:textSize="24sp"/>
</FrameLayout>
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:background="?android:attr/windowBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="确认执行排档"
android:textSize="18sp"
android:textStyle="bold"
android:gravity="center"
android:paddingBottom="15dp"/>
<TextView
android:id="@+id/dialog_schedule_task_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold"
android:paddingBottom="10dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:paddingBottom="5dp"
android:id="@+id/dialog_schedule_current_time"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:paddingBottom="5dp"
android:id="@+id/dialog_schedule_duration"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:paddingBottom="5dp"
android:id="@+id/dialog_schedule_remark"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:paddingTop="10dp"
android:textStyle="bold"
android:id="@+id/dialog_schedule_new_time"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="20dp"
android:gravity="end">
<Button
android:id="@+id/dialog_btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消"
android:layout_marginEnd="10dp"/>
<Button
android:id="@+id/dialog_btn_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确认排档"/>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,174 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:background="?android:attr/windowBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="编辑任务排档"
android:textSize="18sp"
android:textStyle="bold"
android:gravity="center"
android:paddingBottom="15dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="任务名称:"
android:textSize="14sp"
android:paddingBottom="5dp"/>
<EditText
android:id="@+id/dialog_et_task_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入任务名称"
android:inputType="text"
android:padding="10dp"
android:background="@android:drawable/edit_text"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="当前排档时间(yyyy-MM-dd HH):"
android:textSize="14sp"
android:paddingTop="15dp"
android:paddingBottom="5dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<EditText
android:id="@+id/dialog_et_start_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="例如:09:00"
android:inputType="time"
android:padding="10dp"
android:background="@android:drawable/edit_text"/>
<Button
android:id="@+id/dialog_btn_now"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="现在"
android:layout_marginStart="10dp"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="排档幅度:"
android:textSize="14sp"
android:paddingTop="15dp"
android:paddingBottom="5dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<EditText
android:id="@+id/dialog_et_month"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="月份"
android:inputType="number"
android:padding="10dp"
android:background="@android:drawable/edit_text"
android:layout_marginEnd="5dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="月"/>
<EditText
android:id="@+id/dialog_et_day"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="天数"
android:inputType="number"
android:padding="10dp"
android:background="@android:drawable/edit_text"
android:layout_marginStart="10dp"
android:layout_marginEnd="5dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="天"/>
<EditText
android:id="@+id/dialog_et_hour"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="小时"
android:inputType="number"
android:padding="10dp"
android:background="@android:drawable/edit_text"
android:layout_marginStart="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小时"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="备注:"
android:textSize="14sp"
android:paddingTop="15dp"
android:paddingBottom="5dp"/>
<EditText
android:id="@+id/dialog_et_remark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入备注信息"
android:inputType="textMultiLine"
android:minLines="3"
android:gravity="top|start"
android:padding="10dp"
android:background="@android:drawable/edit_text"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="20dp"
android:gravity="end">
<Button
android:id="@+id/dialog_btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消"
android:layout_marginEnd="10dp"/>
<Button
android:id="@+id/dialog_btn_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="保存"/>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/bg_frame"
android:padding="10dp"
android:layout_marginBottom="5dp"
android:id="@+id/itemtaskscheduler_llmain">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="任务:"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"/>
<TextView
android:id="@+id/item_task_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"/>
<Button
android:id="@+id/item_btn_schedule"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="▷"
android:textSize="12sp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical"
android:layout_marginTop="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="排档时间:"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/item_start_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/item_time_diff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FF1976D2"
android:layout_marginStart="10dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="排档幅度:"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_marginLeft="0dp"/>
<TextView
android:id="@+id/item_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="备注:"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/item_remark"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="#F5F5F5"
app:cardElevation="4dp"
app:cardCornerRadius="4dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listviewtableinfoCheckBox1"/>
</androidx.cardview.widget.CardView>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_gradient"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="#FF000000"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_about"
android:title="About"
android:icon="@android:drawable/ic_menu_info_details"
app:showAsAction="ifRoom"/>
</menu>
@@ -1,3 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">排档辅助管理工具</string>
</resources>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- WinBoLL 默认方案 -->
<color name="colorPrimary">#FF196ABC</color>
<color name="colorPrimaryDark">#FF002B57</color>
<color name="colorAccent">#FF80BFFF</color>
<color name="colorToastFrame">#FFA9A9A9</color>
<color name="colorToastShadow">#FF000000</color>
<color name="colorToastBackgroung">#FFFFFFFF</color>
<color name="colorPreNullBackgroung">#FF31D423</color>
<color name="colorCompleteBackgroung">#FF34E4E7</color>
<!-- APPBase 主题必需颜色 -->
<color name="mainWindowBackgroundColor">#FFF5F5F5</color>
<color name="mainWindowTextColor">#FF000000</color>
<color name="toolbarTextColor">#FFFFFFFF</color>
<color name="toolbarBackgroundColor">#FF196ABC</color>
<color name="debugTextColor">#FF808080</color>
<!-- 基础颜色 -->
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
<!-- 排档时间超过当前时间的列表项背景色 -->
<color name="colorScheduleFutureBackground">#FFC8E6C9</color>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">StallHelper</string>
<string name="app_description">LargeStall Stand Auxiliary Management Tool.</string>
</resources>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyStallHelperTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="themeDebug">@style/MyDebugActivityTheme</item>
<item name="aboutViewBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="aboutViewTextColor">?attr/mainWindowTextColor</item>
<item name="aboutViewTitleColor">?attr/mainWindowTextColor</item>
<item name="aboutViewDividerColor">?attr/mainWindowDarkTextColor</item>
<item name="dialogBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="dialogTextColor">?attr/mainWindowTextColor</item>
<item name="toolbarBackgroundColor">@color/toolbarBackgroundColor</item>
<item name="toolbarTextColor">@color/toolbarTextColor</item>
<item name="textViewBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="textViewTextColor">?attr/mainWindowTextColor</item>
<item name="editTextBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="editTextTextColor">?attr/mainWindowTextColor</item>
<item name="scrollViewBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="activityBackgroundColor">?attr/mainWindowBackgroundColor</item>
<item name="activityTextColor">?attr/mainWindowTextColor</item>
<item name="mainWindowBackgroundColor">@color/mainWindowBackgroundColor</item>
<item name="mainWindowTextColor">@color/mainWindowTextColor</item>
<item name="mainWindowDarkBackgroundColor">@color/mainWindowBackgroundColor</item>
<item name="mainWindowDarkTextColor">@color/mainWindowTextColor</item>
</style>
<style name="MyDebugActivityTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">@color/toolbarBackgroundColor</item>
<item name="colorTittle">?attr/mainWindowTextColor</item>
<item name="colorTittleBackgound">@color/toolbarBackgroundColor</item>
<item name="colorText">?attr/debugTextColor</item>
<item name="colorTextBackgound">?attr/mainWindowBackgroundColor</item>
<item name="debugTextColor">@color/debugTextColor</item>
<item name="toolbarTextColor">@color/toolbarTextColor</item>
</style>
</resources>
-37
View File
@@ -1,37 +0,0 @@
# WinBoLL
#### 介绍
WinBoLL 网站浏览器。
#### 软件架构
适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。
也适配安卓应用 [AndroidIDE] 的 Gradle 编译结构。
#### Gradle 编译说明
调试版编译命令 gradle assembleBetaDebug
阶段版编译命令 bash .winboll/bashPublishAPKAddTag.sh winboll
#### 使用说明
3. Termux应用配置:
- 已安装Termux(包名 com.termux );
- 执行  echo "allow-external-apps = true" > ~/.termux/termux.properties
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码 : ZhanGSKen(ZhanGSKen<zhangsken@188.com>)
4. 新建 Pull Request
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
#### 参考文档
-8
View File
@@ -1,8 +0,0 @@
#Created by .winboll/winboll_app_build.gradle
#Fri May 15 08:48:45 GMT 2026
stageCount=2
libraryProject=libwinboll
baseVersion=15.20
publishVersion=15.20.1
buildCount=7
baseBetaVersion=15.20.2
Binary file not shown.
@@ -1,32 +0,0 @@
package cc.winboll.studio.winboll.activities;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.winboll.R;
/**
* Ollama 模型对话窗口
*/
public class OllamaWindowActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ollama_window);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("Ollama 窗口");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_ollama_window, menu);
return true;
}
}
@@ -1,140 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#1E1E1E"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#333333"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.MaterialComponents.ActionBar" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="56dp"
android:layout_marginBottom="48dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ollama 模型对话"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="系统提示:"
android:textColor="#B0B0B0" />
<EditText
android:id="@+id/etSystemPrompt"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#2D2D2D"
android:hint="请输入系统提示"
android:textColor="#FFFFFF"
android:textColorHint="#666666"
android:gravity="top|start"
android:inputType="textMultiLine" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="模型名称:"
android:textColor="#B0B0B0" />
<EditText
android:id="@+id/etModelName"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#2D2D2D"
android:hint="llama3"
android:text="llama3"
android:textColor="#FFFFFF"
android:textColorHint="#666666"
android:singleLine="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="系统消息:"
android:textColor="#B0B0B0" />
<EditText
android:id="@+id/etUserMessage"
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="#2D2D2D"
android:ems="10"
android:gravity="top|start"
android:hint="输入你要发送的消息..."
android:inputType="textMultiLine" />
<EditText
android:id="@+id/etAssistantMessage"
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="#2D2D2D"
android:gravity="top|start"
android:hint="模型响应将显示在这里..."
android:inputType="textMultiLine" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<Button
android:id="@+id/btnSend"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="发送"
android:textColor="#FFFFFF" />
<Button
android:id="@+id/btnStop"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:text="停止"
android:textColor="#FF5252" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_config"
android:title="配置"
android:orderInCategory="100"
app:showAsAction="always" />
</menu>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">WinBoLL+</string>
<string name="app_name_cn1">筋斗云★</string>
<string name="app_name_cn2">金抖云☆</string>
</resources>
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 切换启动入口的快捷菜单 -->
<shortcut
android:shortcutId="switchto_en1"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_en1"
android:shortcutLongLabel="@string/switchto_en1"
android:shortcutDisabledMessage="@string/en1_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_EN1"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_en1" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
<!--<shortcut
android:shortcutId="switchto_cn1"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_cn1"
android:shortcutLongLabel="@string/switchto_cn1"
android:shortcutDisabledMessage="@string/cn1_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_CN1"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_cn1" />
<categories android:name="android.shortcut.conversation" />
</shortcut>-->
<shortcut
android:shortcutId="switchto_cn2"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_cn2"
android:shortcutLongLabel="@string/switchto_cn2"
android:shortcutDisabledMessage="@string/cn2_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_CN2"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_cn2" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
</shortcuts>
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 切换启动入口的快捷菜单 -->
<shortcut
android:shortcutId="switchto_en1"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_en1"
android:shortcutLongLabel="@string/switchto_en1"
android:shortcutDisabledMessage="@string/en1_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_EN1"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_en1" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
<shortcut
android:shortcutId="switchto_cn1"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_cn1"
android:shortcutLongLabel="@string/switchto_cn1"
android:shortcutDisabledMessage="@string/cn1_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_CN1"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_cn1" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
<!--<shortcut
android:shortcutId="switchto_cn2"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_cn2"
android:shortcutLongLabel="@string/switchto_cn2"
android:shortcutDisabledMessage="@string/cn2_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_CN2"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_cn2" />
<categories android:name="android.shortcut.conversation" />
</shortcut>-->
</shortcuts>
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 切换启动入口的快捷菜单 -->
<!--<shortcut
android:shortcutId="switchto_en1"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_en1"
android:shortcutLongLabel="@string/switchto_en1"
android:shortcutDisabledMessage="@string/en1_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_EN1"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_en1" />
<categories android:name="android.shortcut.conversation" />
</shortcut>-->
<shortcut
android:shortcutId="switchto_cn1"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_cn1"
android:shortcutLongLabel="@string/switchto_cn1"
android:shortcutDisabledMessage="@string/cn1_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_CN1"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_cn1" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
<shortcut
android:shortcutId="switchto_cn2"
android:enabled="true"
android:icon="@drawable/ic_launcher"
android:shortcutShortLabel="@string/switchto_cn2"
android:shortcutLongLabel="@string/switchto_cn2"
android:shortcutDisabledMessage="@string/cn2_switch_disabled">
<intent
android:action="cc.winboll.studio.winboll.App.ACTION_SWITCHTO_CN2"
android:targetPackage="cc.winboll.studio.winboll.beta"
android:targetClass="cc.winboll.studio.winboll.activities.ShortcutActionActivity"
android:data="switchto_cn2" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
</shortcuts>
-339
View File
@@ -1,339 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="cc.winboll.studio.winboll"
android:sharedUserId="com.termux">
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 发送持久广播 -->
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<!-- 对正在运行的应用重新排序 -->
<uses-permission android:name="android.permission.REORDER_TASKS"/>
<!-- 计算应用存储空间 -->
<uses-permission
android:name="android.permission.GET_PACKAGE_SIZE"/>
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:roundIcon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/MyAppTheme"
android:resizeableActivity="true"
android:name=".App"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
</intent-filter>
</activity>
<activity android:name=".activities.ShortcutActionActivity"/>
<activity-alias
android:name=".MainActivityEN1"
android:targetActivity=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcutsmainen1"/>
</activity-alias>
<activity-alias
android:name=".MainActivityCN1"
android:targetActivity=".MainActivity"
android:exported="true"
android:label="@string/app_name_cn1"
android:icon="@drawable/ic_winboll_jindouyun1"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcutsmaincn1"/>
</activity-alias>
<activity-alias
android:name=".MainActivityCN2"
android:targetActivity=".MainActivity"
android:exported="true"
android:label="@string/app_name_cn2"
android:icon="@drawable/ic_winboll_jindouyun2"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcutsmaincn2"/>
</activity-alias>
<activity
android:name=".activities.WinBoLLUnitTestActivity"
android:label="@string/app_name"
android:exported="true"
android:resizeableActivity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".activities.NewActivity"
android:label="NewActivity"
android:exported="true"
android:resizeableActivity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/>
<activity
android:name=".activities.New2Activity"
android:label="New2Activity"
android:exported="true"
android:resizeableActivity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/>
<service
android:name=".MyTileService"
android:exported="true"
android:label="@string/tileservice_name"
android:icon="@drawable/ic_launcher"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".services.MainService"
android:exported="true"/>
<service
android:name="cc.winboll.studio.appbase.services.TestDemoBindService"
android:exported="true"/>
<service
android:name="cc.winboll.studio.appbase.services.TestDemoService"
android:exported="true"/>
<service android:name=".services.AssistantService"/>
<receiver
android:name="cc.winboll.studio.appbase.receivers.MainReceiver"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/>
</intent-filter>
</receiver>
<receiver
android:name=".widgets.APPNewsWidget"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_WAKEUP_SERVICE"/>
<action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_RELOAD_REPORT"/>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_provider_info_sos"/>
</receiver>
<receiver
android:name=".receivers.APPNewsWidgetClickListener"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_PRE"/>
<action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_NEXT"/>
</intent-filter>
</receiver>
<service
android:name=".SimpleOperateSignalCenterService"
android:exported="true">
</service>
<service
android:name=".services.TestService"
android:exported="true"/>
<receiver
android:name=".receiver.MyBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.libappbase.action.SOS"/>
</intent-filter>
</receiver>
<receiver
android:name=".widgets.StatusWidget"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="cc.winboll.studio.libappbase.widgets.StatusWidget.ACTION_STATUS_UPDATE"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_provider_info_status"/>
</receiver>
<receiver
android:name=".widgets.StatusWidgetClickListener"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.libappbase.widgets.StatusWidgetClickListener.ACTION_IVAPP"/>
</intent-filter>
</receiver>
<service android:name="cc.winboll.studio.libappbase.sos.SOSCenter"/>
<receiver
android:name="cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver"/>
</intent-filter>
</receiver>
<activity android:name="cc.winboll.studio.libappbase.activities.YunActivity"/>
<activity android:name="cc.winboll.studio.libappbase.activities.LogonActivity"/>
<activity android:name="cc.winboll.studio.winboll.activities.AboutActivity"/>
<activity android:name="cc.winboll.studio.winboll.activities.SettingsActivity"/>
<activity android:name="cc.winboll.studio.winboll.unittest.TestWeWorkSpecSDK"/>
<activity android:name="cc.winboll.studio.winboll.activities.WXPayActivity"/>
<activity android:name="cc.winboll.studio.winboll.activities.PatternLockActivity"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.winboll.activities.PatternLockActivity.ACTION_OPEN_PATTERN"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="cc.winboll.studio.winboll.unittest.TermuxEnvTestActivity"/>
<activity
android:name=".termux.NfcTermuxBridgeActivity"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.winboll.termux.NfcTermuxBridgeActivity.ACTION_BUILD"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="cc.winboll.studio.winboll.applications.MyTermuxActivity"
android:label="@string/my_termux_activity"
android:exported="true"/>
</application>
</manifest>
@@ -1,366 +0,0 @@
package cc.winboll.studio.winboll;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.ToastUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
public class App extends GlobalApplication {
public static final String TAG = "App";
public static final String COMPONENT_EN1 = "cc.winboll.studio.winboll.MainActivityEN1";
public static final String COMPONENT_CN1 = "cc.winboll.studio.winboll.MainActivityCN1";
public static final String COMPONENT_CN2 = "cc.winboll.studio.winboll.MainActivityCN2";
public static final String ACTION_SWITCHTO_EN1 = "cc.winboll.studio.winboll.App.ACTION_SWITCHTO_EN1";
public static final String ACTION_SWITCHTO_CN1 = "cc.winboll.studio.winboll.App.ACTION_SWITCHTO_CN1";
public static final String ACTION_SWITCHTO_CN2 = "cc.winboll.studio.winboll.App.ACTION_SWITCHTO_CN2";
private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper());
@Override
public void onCreate() {
super.onCreate();
setIsDebugging(BuildConfig.DEBUG);
//setIsDebugging(false);
WinBoLLActivityManager.init(this);
// 初始化 Toast 框架
ToastUtils.init(this);
// 设置 Toast 布局样式
//ToastUtils.setView(R.layout.view_toast);
//ToastUtils.setStyle(new WhiteToastStyle());
//ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
//CrashHandler.getInstance().registerGlobal(this);
//CrashHandler.getInstance().registerPart(this);
}
@Override
public void onTerminate() {
super.onTerminate();
ToastUtils.release();
}
public static void write(InputStream input, OutputStream output) throws IOException {
byte[] buf = new byte[1024 * 8];
int len;
while ((len = input.read(buf)) != -1) {
output.write(buf, 0, len);
}
}
public static void write(File file, byte[] data) throws IOException {
File parent = file.getParentFile();
if (parent != null && !parent.exists()) parent.mkdirs();
ByteArrayInputStream input = new ByteArrayInputStream(data);
FileOutputStream output = new FileOutputStream(file);
try {
write(input, output);
} finally {
closeIO(input, output);
}
}
public static String toString(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
write(input, output);
try {
return output.toString("UTF-8");
} finally {
closeIO(input, output);
}
}
public static void closeIO(Closeable... closeables) {
for (Closeable closeable : closeables) {
try {
if (closeable != null) closeable.close();
} catch (IOException ignored) {}
}
}
public static class CrashHandler {
public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler();
private static CrashHandler sInstance;
private PartCrashHandler mPartCrashHandler;
public static CrashHandler getInstance() {
if (sInstance == null) {
sInstance = new CrashHandler();
}
return sInstance;
}
public void registerGlobal(Context context) {
registerGlobal(context, null);
}
public void registerGlobal(Context context, String crashDir) {
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl(context.getApplicationContext(), crashDir));
}
public void unregister() {
Thread.setDefaultUncaughtExceptionHandler(DEFAULT_UNCAUGHT_EXCEPTION_HANDLER);
}
public void registerPart(Context context) {
unregisterPart(context);
mPartCrashHandler = new PartCrashHandler(context.getApplicationContext());
MAIN_HANDLER.postAtFrontOfQueue(mPartCrashHandler);
}
public void unregisterPart(Context context) {
if (mPartCrashHandler != null) {
mPartCrashHandler.isRunning.set(false);
mPartCrashHandler = null;
}
}
private static class PartCrashHandler implements Runnable {
private final Context mContext;
public AtomicBoolean isRunning = new AtomicBoolean(true);
public PartCrashHandler(Context context) {
this.mContext = context;
}
@Override
public void run() {
while (isRunning.get()) {
try {
Looper.loop();
} catch (final Throwable e) {
e.printStackTrace();
if (isRunning.get()) {
MAIN_HANDLER.post(new Runnable(){
@Override
public void run() {
Toast.makeText(mContext, e.toString(), Toast.LENGTH_LONG).show();
}
});
} else {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
} else {
throw new RuntimeException(e);
}
}
}
}
}
}
private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler {
private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss");
private final Context mContext;
private final File mCrashDir;
public UncaughtExceptionHandlerImpl(Context context, String crashDir) {
this.mContext = context;
this.mCrashDir = TextUtils.isEmpty(crashDir) ? new File(mContext.getExternalCacheDir(), "crash") : new File(crashDir);
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
try {
String log = buildLog(throwable);
writeLog(log);
try {
Intent intent = new Intent(mContext, CrashActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_TEXT, log);
mContext.startActivity(intent);
} catch (Throwable e) {
e.printStackTrace();
writeLog(e.toString());
}
throwable.printStackTrace();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Throwable e) {
if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable);
}
}
private String buildLog(Throwable throwable) {
String time = DATE_FORMAT.format(new Date());
String versionName = "unknown";
long versionCode = 0;
try {
PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
versionName = packageInfo.versionName;
versionCode = Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : packageInfo.versionCode;
} catch (Throwable ignored) {}
LinkedHashMap<String, String> head = new LinkedHashMap<String, String>();
head.put("Time Of Crash", time);
head.put("Device", String.format("%s, %s", Build.MANUFACTURER, Build.MODEL));
head.put("Android Version", String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
head.put("App Version", String.format("%s (%d)", versionName, versionCode));
head.put("Kernel", getKernel());
head.put("Support Abis", Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null ? Arrays.toString(Build.SUPPORTED_ABIS): "unknown");
head.put("Fingerprint", Build.FINGERPRINT);
StringBuilder builder = new StringBuilder();
for (String key : head.keySet()) {
if (builder.length() != 0) builder.append("\n");
builder.append(key);
builder.append(" : ");
builder.append(head.get(key));
}
builder.append("\n\n");
builder.append(Log.getStackTraceString(throwable));
return builder.toString();
}
private void writeLog(String log) {
String time = DATE_FORMAT.format(new Date());
File file = new File(mCrashDir, "crash_" + time + ".txt");
try {
write(file, log.getBytes("UTF-8"));
} catch (Throwable e) {
e.printStackTrace();
}
}
private static String getKernel() {
try {
return App.toString(new FileInputStream("/proc/version")).trim();
} catch (Throwable e) {
return e.getMessage();
}
}
}
}
public static final class CrashActivity extends Activity {
private String mLog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(android.R.style.Theme_DeviceDefault);
setTitle("App Crash");
mLog = getIntent().getStringExtra(Intent.EXTRA_TEXT);
ScrollView contentView = new ScrollView(this);
contentView.setFillViewport(true);
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(this);
TextView textView = new TextView(this);
int padding = dp2px(16);
textView.setPadding(padding, padding, padding, padding);
textView.setText(mLog);
textView.setTextIsSelectable(true);
textView.setTypeface(Typeface.DEFAULT);
textView.setLinksClickable(true);
horizontalScrollView.addView(textView);
contentView.addView(horizontalScrollView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
setContentView(contentView);
}
private void restart() {
Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
finish();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
private static int dp2px(float dpValue) {
final float scale = Resources.getSystem().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, android.R.id.copy, 0, android.R.string.copy)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.copy:
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
restart();
}
}
}
@@ -1,97 +0,0 @@
package cc.winboll.studio.winboll;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/03/28 19:12:12
* @Describe 应用主要服务组件类守护进程服务组件类
*/
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import cc.winboll.studio.libaes.models.WinBoLLClientServiceBean;
import cc.winboll.studio.winboll.WinBoLLClientService;
import cc.winboll.studio.winboll.utils.ServiceUtils;
public class AssistantService extends Service {
public final static String TAG = "AssistantService";
WinBoLLClientServiceBean mWinBoLLServiceBean;
MyServiceConnection mMyServiceConnection;
volatile boolean mIsServiceRunning;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mWinBoLLServiceBean = WinBoLLClientServiceBean.loadWinBoLLClientServiceBean(this);
if (mMyServiceConnection == null) {
mMyServiceConnection = new MyServiceConnection();
}
// 设置运行参数
mIsServiceRunning = false;
run();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
run();
return START_STICKY;
}
@Override
public void onDestroy() {
mIsServiceRunning = false;
super.onDestroy();
}
//
// 运行服务内容
//
void run() {
mWinBoLLServiceBean = WinBoLLClientServiceBean.loadWinBoLLClientServiceBean(this);
if (mWinBoLLServiceBean.isEnable()) {
if (mIsServiceRunning == false) {
// 设置运行状态
mIsServiceRunning = true;
// 唤醒和绑定主进程
wakeupAndBindMain();
}
}
}
//
// 唤醒和绑定主进程
//
void wakeupAndBindMain() {
if (ServiceUtils.isServiceAlive(getApplicationContext(), WinBoLLClientService.class.getName()) == false) {
startForegroundService(new Intent(AssistantService.this, WinBoLLClientService.class));
}
bindService(new Intent(AssistantService.this, WinBoLLClientService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
}
//
// 主进程与守护进程连接时需要用到此类
//
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
mWinBoLLServiceBean = WinBoLLClientServiceBean.loadWinBoLLClientServiceBean(AssistantService.this);
if (mWinBoLLServiceBean.isEnable()) {
wakeupAndBindMain();
}
}
}
}
@@ -1,35 +0,0 @@
package cc.winboll.studio.winboll;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/03/28 19:11:27
* @Describe WinBoLL UI 状态图标枚举
*/
import cc.winboll.studio.libaes.R;
public enum EWUIStatusIconDrawable {
NORMAL(0),
NEWS(1)
;
static final String TAG = "WUIStatusIconDrawable";
static String[] _mlistCNName = { "正常", "新的消息" };
private int value = 0;
private EWUIStatusIconDrawable(int value) { //必须是private的,否则编译错误
this.value = value;
}
public static int getIconDrawableId(EWUIStatusIconDrawable drawableId) {
int res;
switch(drawableId){
case NEWS :
res = R.drawable.ic_winbollbeta;
break;
default :
res = R.drawable.ic_winboll;
}
return res;
}
}
@@ -1,221 +0,0 @@
package cc.winboll.studio.winboll;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import cc.winboll.studio.libaes.activitys.DrawerFragmentActivity;
import cc.winboll.studio.libaes.models.DrawerMenuBean;
import cc.winboll.studio.libaes.utils.AESThemeUtil;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.winboll.R;
import cc.winboll.studio.winboll.activities.AboutActivity;
import cc.winboll.studio.winboll.activities.SettingsActivity;
import cc.winboll.studio.winboll.applications.MyTermuxActivity;
import cc.winboll.studio.winboll.fragments.BrowserFragment;
import cc.winboll.studio.winboll.unittest.TermuxEnvTestActivity;
import java.util.ArrayList;
public class MainActivity extends DrawerFragmentActivity {
public static final String TAG = "MainActivity";
BrowserFragment mBrowserFragment;
// ------------------- 新增:Handler 消息定义(接收URL历史更新消息) -------------------
// 消息标识:URL加载历史更新(刷新抽屉菜单的历史列表)
public static final int MSG_URLLOADHISTORY_UPDATE = 1002;
// 自定义Handler(接收应用内消息,如BrowserFragment发送的历史更新消息)
private static Handler _mMainHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(cc.winboll.studio.winboll.theme.WinBoLLThemeUtil.getThemeTypeID(this));
super.onCreate(savedInstanceState);
initMainHandler();
if (mBrowserFragment == null) {
String externalUrl = extractExternalUrl(getIntent());
if (externalUrl != null) {
mBrowserFragment = BrowserFragment.newInstance(externalUrl);
} else {
mBrowserFragment = BrowserFragment.newInstance();
}
addFragment(mBrowserFragment);
}
showFragment(mBrowserFragment);
}
// @Override
// protected void onNewIntent(Intent intent) {
// super.onNewIntent(intent);
// String externalUrl = extractExternalUrl(intent);
// if (externalUrl != null && mBrowserFragment != null && mBrowserFragment.getBrowserHandler() != null) {
// Message msg = Message.obtain();
// msg.what = BrowserFragment.MSG_OPEN_URL;
// msg.obj = externalUrl;
// mBrowserFragment.getBrowserHandler().sendMessage(msg);
// }
// }
private String extractExternalUrl(Intent intent) {
if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
Uri uri = intent.getData();
if (uri != null) {
return uri.toString();
}
}
return null;
}
public static void sendMessage(Message msg) {
_mMainHandler.sendMessage(msg);
}
/**
* 初始化Handler(接收MSG_URLLOADHISTORY_UPDATE消息,刷新抽屉历史菜单)
*/
private void initMainHandler() {
// 清理旧数据
if (_mMainHandler != null) {
_mMainHandler.removeCallbacksAndMessages(null);
_mMainHandler = null;
}
// Java 7 匿名内部类实现Handler(主线程创建,安全更新UI/抽屉菜单)
_mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_URLLOADHISTORY_UPDATE:
// 处理URL历史更新消息:刷新抽屉菜单的历史列表
LogUtils.d(TAG, "收到URL历史更新消息,刷新抽屉菜单");
refreshUrlHistoryDrawerMenu();
break;
default:
break;
}
}
};
}
@Override
public void initDrawerMenuItemList(ArrayList<DrawerMenuBean> listDrawerMenu) {
super.initDrawerMenuItemList(listDrawerMenu);
//LogUtils.d(TAG, "initDrawerMenuItemList");
// 加载URL历史菜单(初始化时加载)
refreshUrlHistoryDrawerMenu();
notifyDrawerMenuDataChanged();
}
@Override
public void reinitDrawerMenuItemList(ArrayList<DrawerMenuBean> listDrawerMenu) {
super.reinitDrawerMenuItemList(listDrawerMenu);
//LogUtils.d(TAG, "reinitDrawerMenuItemList");
// 重新加载URL历史菜单(菜单重置时加载)
refreshUrlHistoryDrawerMenu();
notifyDrawerMenuDataChanged();
}
void loadUrlLoadHistotyMenu(ArrayList<DrawerMenuBean> listDrawerMenu) {
listDrawerMenu.clear();
if (BrowserFragment._mUrlLoadHistory != null) {
for (String url : BrowserFragment._mUrlLoadHistory) {
listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, url));
}
}
}
// ------------------- 新增:刷新URL历史抽屉菜单(提取独立方法,复用) -------------------
private void refreshUrlHistoryDrawerMenu() {
// 获取抽屉菜单列表,重新加载历史数据并刷新
ArrayList<DrawerMenuBean> drawerMenuList = super.malDrawerMenuItem; // 假设父类提供获取菜单列表的方法
if (drawerMenuList != null) {
loadUrlLoadHistotyMenu(drawerMenuList); // 重新加载更新后的历史数据
notifyDrawerMenuDataChanged(); // 通知抽屉菜单刷新UI
}
}
@Override
public DrawerFragmentActivity.ActivityType initActivityType() {
return DrawerFragmentActivity.ActivityType.Main;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_main, menu);
if (App.isDebugging()) {
getMenuInflater().inflate(R.menu.toolbar_test, menu);
}
return super.onCreateOptionsMenu(menu);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
super.onItemClick(parent, view, position, id);
if (mBrowserFragment != null && mBrowserFragment.getBrowserHandler() != null) {
Message msg = Message.obtain();
msg.what = BrowserFragment.MSG_HISTORY_POSITION;
msg.obj = position;
mBrowserFragment.getBrowserHandler().sendMessage(msg);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (AESThemeUtil.onWinBoLLThemeItemSelected(this, item)) {
recreate();
} else {
int nItemId = item.getItemId();
if (nItemId == R.id.item_home) {
if (mBrowserFragment != null && mBrowserFragment.getBrowserHandler() != null) {
Message msg = Message.obtain();
msg.what = BrowserFragment.MSG_HOMEPAGE;
mBrowserFragment.getBrowserHandler().sendMessage(msg);
}
} else if (nItemId == R.id.item_settings) {
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), SettingsActivity.class);
} else if (nItemId == R.id.item_about) {
Intent intent = new Intent(getApplicationContext(), AboutActivity.class);
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), intent, AboutActivity.class);
} else if (nItemId == R.id.item_mytermux) {
Intent intent = new Intent(getApplicationContext(), MyTermuxActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else if (nItemId == R.id.item_termux_env_test) {
Intent intent = new Intent(getApplicationContext(), TermuxEnvTestActivity.class);
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), intent, AboutActivity.class);
} else if (nItemId == R.id.item_library_activity) {
Intent intent = new Intent(getApplicationContext(), cc.winboll.studio.libwinboll.WinBoLLLibraryActivity.class);
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), intent, AboutActivity.class);
} else {
return super.onOptionsItemSelected(item);
}
}
return true;
}
// ------------------- 新增:对外提供Handler(供其他组件发送消息,如BrowserFragment -------------------
public Handler getMainHandler() {
return _mMainHandler;
}
// ------------------- 新增:生命周期管理(防止Handler内存泄漏) -------------------
@Override
protected void onDestroy() {
super.onDestroy();
// 清除Handler所有消息和回调,避免内存泄漏
if (_mMainHandler != null) {
_mMainHandler.removeCallbacksAndMessages(null);
_mMainHandler = null;
}
}
}
@@ -1,80 +0,0 @@
package cc.winboll.studio.winboll;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/02/13 19:30:10
*/
import android.content.Context;
import cc.winboll.studio.winboll.R;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import cc.winboll.studio.winboll.models.MainServiceBean;
import cc.winboll.studio.winboll.services.MainService;
public class MyTileService extends TileService {
public static final String TAG = "MyTileService";
volatile static MyTileService _MyTileService;
@Override
public void onStartListening() {
super.onStartListening();
_MyTileService = this;
Tile tile = getQsTile();
MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class);
if (bean != null && bean.isEnable()) {
//MainService.startMainService(context);
tile.setState(Tile.STATE_ACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud));
} else {
//MainService.stopMainService(context);
tile.setState(Tile.STATE_INACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline));
}
tile.updateTile();
// Tile tile = getQsTile();
// tile.setState(Tile.STATE_INACTIVE);
// tile.setLabel(getString(R.string.tileservice_name));
// tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline));
// tile.updateTile();
}
@Override
public void onClick() {
super.onClick();
Tile tile = getQsTile();
MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class);
if (bean == null) {
bean = new MainServiceBean();
}
if (tile.getState() == Tile.STATE_ACTIVE) {
bean.setIsEnable(false);
MainServiceBean.saveBean(this, bean);
MainService.stopMainService(this);
} else if (tile.getState() == Tile.STATE_INACTIVE) {
bean.setIsEnable(true);
MainServiceBean.saveBean(this, bean);
MainService.startMainService(this);
}
updateServiceIconStatus(this);
}
public static void updateServiceIconStatus(Context context) {
if (_MyTileService == null) {
return;
}
Tile tile = _MyTileService.getQsTile();
MainServiceBean bean = MainServiceBean.loadBean(context, MainServiceBean.class);
if (bean != null && bean.isEnable()) {
tile.setState(Tile.STATE_ACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud));
} else {
tile.setState(Tile.STATE_INACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud_outline));
}
tile.updateTile();
}
}
@@ -1,40 +0,0 @@
package cc.winboll.studio.winboll;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/05/10 10:13
* @Describe WinBoLL 系列应用通用管理类
*/
import android.content.Context;
import android.content.Intent;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.winboll.models.WinBoLLModel;
public class WinBoLL {
public static final String TAG = "WinBoLL";
public static final String ACTION_BIND = WinBoLL.class.getName() + ".ACTION_BIND";
public static final String EXTRA_WINBOLLMODEL = "EXTRA_WINBOLLMODEL";
public static void bindToAPPBase(Context context, String appMainService) {
LogUtils.d(TAG, "bindToAPPBase(...)");
String toPackage = "cc.winboll.studio.appbase";
startBind(context, toPackage, appMainService);
}
public static void bindToAPPBaseBeta(Context context, String appMainService) {
LogUtils.d(TAG, "bindToAPPBaseBeta(...)");
String toPackage = "cc.winboll.studio.appbase.beta";
startBind(context, toPackage, appMainService);
}
static void startBind(Context context, String toPackage, String appMainService) {
Intent intent = new Intent(ACTION_BIND);
intent.putExtra(EXTRA_WINBOLLMODEL, (new WinBoLLModel(toPackage, appMainService)).toString());
intent.setPackage(toPackage);
LogUtils.d(TAG, String.format("ACTION_BIND :\nTo Package : %s\nAPP Main Service : %s", toPackage, appMainService));
context.sendBroadcast(intent);
}
}
@@ -1,21 +0,0 @@
package cc.winboll.studio.winboll;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
/**
* @Author ZhanGSKen
* @Date 2025/05/03 19:28
*/
public class WinBoLLClientService extends Service {
public static final String TAG = "WinBoLLClientService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

Some files were not shown because too many files have changed in this diff Show More