Compare commits
14 Commits
branch_new
...
dev-lxj
| Author | SHA1 | Date | |
|---|---|---|---|
| d3bd838753 | |||
| 02715f1346 | |||
| c1d77850f1 | |||
| 773c3fc8b4 | |||
| d0337a723c | |||
| 96c679528e | |||
| 6b9490cceb | |||
| 877ef5ea05 | |||
| 771138d34c | |||
| 520bc8e1bb | |||
| f5377127ce | |||
| f4f04b59a8 | |||
| a993a7710f | |||
| a5ebc83dea |
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
.idea/
|
||||
*.iml
|
||||
build/
|
||||
local.properties
|
||||
.gradle/
|
||||
.externalNativeBuild/
|
||||
.DS_Store
|
||||
*.dm
|
||||
*.log
|
||||
3
.idea/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
2
.idea/.name
generated
@@ -1 +1 @@
|
||||
秘地
|
||||
羽声语音
|
||||
6
.idea/AndroidProjectSystem.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AndroidProjectSystem">
|
||||
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
||||
18
.idea/deploymentTargetSelector.xml
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetSelector">
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2025-11-06T06:22:54.522558600Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="Default" identifier="serial=emulator-5554;connection=1b58820a" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
</project>
|
||||
33
.idea/gradle.xml
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$/yusheng-android" />
|
||||
<option name="gradleJvm" value="#JAVA_HOME" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$/yusheng-android" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/Loadinglibrary" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/app" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/moduleLogin" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/moduleUtil" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/modulecircle" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/modulemain" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/modulenews" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/moduleroom" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/moduletablayout" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/modulevocal" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/modulevoice" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/timcommon" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/tuichat" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/tuiconversation" />
|
||||
<option value="$PROJECT_DIR$/yusheng-android/tuicore" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$/yusheng-android" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="ms-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
17
.idea/runConfigurations.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/yusheng-android" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,837 +0,0 @@
|
||||
<!-- saved from url=(0051)https://vespa.qxyushen.top//api/Page/page_show?id=4 -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<style>.Po4BvhR1CK2tJaywJ6AN path {
|
||||
fill: var(--icon-path-fill);
|
||||
}
|
||||
.Oz4yDjua3Qe6thqkZYf_ path {
|
||||
transition: 0.2s all;
|
||||
}
|
||||
.Oz4yDjua3Qe6thqkZYf_:hover path {
|
||||
fill: var(--icon-hover-fill);
|
||||
}
|
||||
</style>
|
||||
<style>/* !!!切勿直接改动该文件,该文件由 generator.ts 自动生成!!! */
|
||||
/* !!! DONT MODIFY THIS FILE DIRECTLY, THIS FILE IS GENERATED BY generator.ts AUTOMATICALLY !!! */
|
||||
.ibW4Oa5B7s2zJKKZ4pCg {
|
||||
user-select: none;
|
||||
}
|
||||
.AtqKyJetjrG4smuk35Np {
|
||||
max-width: 346px;
|
||||
width: auto;
|
||||
height: 36px;
|
||||
background-color: var(--quark-style-white-color, #fff);
|
||||
padding-left: 10px;
|
||||
padding-right: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid var(--quark-style-gray-20-color, rgba(6, 10, 38, 0.12));
|
||||
box-shadow: 0 12px 32px -6px var(--quark-style-gray-30-fixed-color, rgba(6, 10, 38, 0.24));
|
||||
border-radius: 10px;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .g6iGsZa_KHMeW2yICzQQ {
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .e4UXx38MPgfHdym_Lzt0 {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
height: 28px;
|
||||
padding: 0 6px;
|
||||
margin-right: 2px;
|
||||
border-radius: 6px;
|
||||
column-gap: 4px;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .e4UXx38MPgfHdym_Lzt0:hover:not(.ibW4Oa5B7s2zJKKZ4pCg .kNOcXLDT_cCrcoY8LTm8) {
|
||||
background: var(--quark-style-gray-10-color, rgba(6, 10, 38, 0.06));
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .kNOcXLDT_cCrcoY8LTm8 {
|
||||
cursor: default;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .kNOcXLDT_cCrcoY8LTm8 .Va3czASiR9Zztyl_lD4M {
|
||||
color: var(--quark-style-gray-40-color, rgba(6, 10, 38, 0.4)) !important;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .e4UXx38MPgfHdym_Lzt0 .Va3czASiR9Zztyl_lD4M {
|
||||
font-size: 12px;
|
||||
color: var(--quark-style-gray-color, #060A26);
|
||||
line-height: 16px;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .llw0qsmiI_08u93bFdNg {
|
||||
position: relative;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
overflow: visible !important;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .LEo8kpqIERehkv8AhAfG {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
overflow: visible !important;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .LEo8kpqIERehkv8AhAfG:hover {
|
||||
background: var(--quark-style-gray-10-color, rgba(6, 10, 38, 0.06));
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .zoNmooxAnbLEJSN8m1Jg {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 110px;
|
||||
max-height: 136px;
|
||||
height: auto;
|
||||
top: 36px;
|
||||
right: -5px;
|
||||
padding: 4px 0;
|
||||
background-color: var(--quark-style-white-color, #fff);
|
||||
border: 1px solid var(--quark-style-gray-20-color, rgba(6, 10, 38, 0.12));
|
||||
box-shadow: 0 4px 16px -6px var(--quark-style-gray-20-fixed-color, rgba(6, 10, 38, 0.12));
|
||||
border-radius: 8px;
|
||||
overflow: visible !important;
|
||||
row-gap: 4px;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .O1imPofna4elG_8NcQnR {
|
||||
top: -77px;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .mdH0IY7jS3Swn5vdX6tz {
|
||||
width: 102px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
cursor: pointer;
|
||||
column-gap: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .mdH0IY7jS3Swn5vdX6tz:hover:not(.ibW4Oa5B7s2zJKKZ4pCg .dEdHLVmn_L2GAzb_cmwt) {
|
||||
background: var(--quark-style-gray-10-color, rgba(6, 10, 38, 0.06));
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .dEdHLVmn_L2GAzb_cmwt {
|
||||
cursor: default;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .dEdHLVmn_L2GAzb_cmwt .zEraruudgjR2MToGu4Kw {
|
||||
color: var(--quark-style-gray-40-color, rgba(6, 10, 38, 0.4)) !important;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .XfCMwvO0DsqFCeyzPYP2 {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .zEraruudgjR2MToGu4Kw {
|
||||
font-size: 12px;
|
||||
color: var(--quark-style-gray-color, #060A26);
|
||||
}
|
||||
.ibW4Oa5B7s2zJKKZ4pCg .KZeoAuXbMIkWzOT4PcH5 {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: var(--quark-style-gray-10-color, rgba(6, 10, 38, 0.06));
|
||||
}
|
||||
.ZL32C_XdLL8UQRZ3zObd {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.u5llx7cIQZLdrjP5Vag1 {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 16px;
|
||||
cursor: pointer;
|
||||
margin-right: 12px;
|
||||
background: var(--quark-style-gray-60-color, rgba(6, 10, 38, 0.6));
|
||||
}
|
||||
.ZL32C_XdLL8UQRZ3zObd .LEo8kpqIERehkv8AhAfG {
|
||||
border-radius: 16px !important;
|
||||
background: var(--quark-style-gray-60-color, rgba(6, 10, 38, 0.6)) !important;
|
||||
}
|
||||
.ZL32C_XdLL8UQRZ3zObd .zoNmooxAnbLEJSN8m1Jg {
|
||||
right: 0 !important;
|
||||
}
|
||||
.ZL32C_XdLL8UQRZ3zObd {
|
||||
overflow: visible !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body><p><strong>羽声语音直播隐私保护政策</strong></p>
|
||||
<p><strong>本版本更新日期:2025年【10】月【27】日</strong></p>
|
||||
<p><strong>本版本生效日期:2025年【10】月【27】日</strong></p>
|
||||
<p><strong>引言:</strong></p>
|
||||
<p style="text-align: left;"><strong>“羽声语音”APP 的运营主体系陕西启星汇申网络科技有限公司(以下简称“我们”&
|
||||
”羽声”)深知个人信息对您的重要性,并会尽力保护您的个人信息安全可靠,我们致力于维持您对我们的信任,恪守以下原则,保护您的个人信息:权责一致原则,目的明确原则,选择同意原则,最少够用原则,确保安全原则,主体参与原则,公开透明原则等。同时我们承诺,我们将按业界成熟的安全解决方案,采取相应的安全保护措施来保护您的个人信息。鉴此,我们制定本《隐私政策》(下称“本政策
|
||||
/ 本隐私政策”)并提醒您: 本政策适用于羽声语音语音软件及相关服务。
|
||||
需要特别说明的是,本政策不适用于其他第三方向您提供的服务,也不适用于已另行独立设置隐私权政策的产品或服务。
|
||||
在使用羽声语音语音软件或服务前,请您务必仔细阅读并透彻理解本政策,特别是以粗体/粗体下划线标识的条款,您应重点阅读,在确认充分理解并同意后使用相关产品或服务。若您拒绝本政策,仅能进入访客态进行浏览。为保障软件及服务的安全运行,呱友在相应功能点触发时会收集相关设备信息及权限。如对本政策内容有任何疑问、意见或建议,您可通过呱友提供的各种联系方式与我们联系。
|
||||
我们非常重视用户个人信息的保护,并且将以勤勉和审慎的义务对待这些信息。您在下载、安装、开启、浏览、注册、登录、使用(以下统称“使用”)本公司软件及相关服务时,本公司将按照本《隐私政策》收集、保存、使用、共享、披露及保护您的个人信息鉴此,我们希望通过本《隐私政策》向您介绍我们对您个人信息的处理方式并提醒您:
|
||||
在使用“羽声”各项产品或服务前,请您留意重点阅读。若您认为本协议中的加粗条款可能会导致您的部分或全部权利或权益受损,请您务必再次仔细阅读,在确保您已经理解、接受了加粗条款的前提下,继续使用本公司服务。如对本政策内容有任何疑问、意见或建议,您可通过提供的各种联系方式与我们联系。</strong>
|
||||
</p>
|
||||
<p><strong>本政策将帮助您了解如下内容:</strong></p>
|
||||
<p><strong>一、定义及适用范围</strong></p>
|
||||
<p><strong>二、我们如何收集和使用您的个人信息</strong></p>
|
||||
<p><strong>三、我们如何使用Cookie和第三方H5页面</strong></p>
|
||||
<p><strong>四、我们如何共享、转让、公开披露您的个人信息</strong></p>
|
||||
<p><strong>五、我们如何存储和保护您的个人信息</strong></p>
|
||||
<p><strong>六、您如何管理您的个人信息</strong></p>
|
||||
<p><strong>七、未成年人保护</strong></p>
|
||||
<p><strong>八、本政策的更新</strong></p>
|
||||
<p><strong>九、联系我们</strong></p>
|
||||
<p><strong>十、其他</strong></p>
|
||||
<p><strong>【特别提示】请您在使用我们各项产品或服务前,仔细阅读并透彻理解本政策,特别是以粗体/下划线/粗体下划线等有特殊标识的条款,您应重点阅读,在确认充分理解并同意后使用相关产品或服务。如果您不同意我们收集您的任何个人信息,您应当立即停止使用并退出羽声语音直播。当您使用或继续使用我们的产品或服务时,即表示您同意我们按照本政策来处理您的相关信息。</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>如对本政策内容有任何疑问,您可以通过本政策中“联系我们”一节提供的联系方式与我们联系。</strong>
|
||||
</p>
|
||||
<p><strong>一、定义及适用范围</strong></p>
|
||||
<p><strong>(一)定义</strong></p>
|
||||
<p><strong>1、羽声语音软件及相关服务:指由陕西启星汇申网络科技有限公司陕西省咸阳市高新技术产业开发区高科三路科技企业孵化园3栋4层
|
||||
及其关联方通过合法拥有并运营的、标注名称为羽声语音、羽声语音极速版的客户端应用程序、APP、微信小程序、微信公众号、羽声语音官方网站( </strong><u>https://golden-llama-1g494r.mysxl.cn/</u>
|
||||
<strong>)、通过APK、SDK、API等方式向您提供的软件和/或服务及随技术发展出现的新形态向您提供的产品与服务。</strong>
|
||||
</p>
|
||||
<p><strong>2、关联方</strong><span style="color: rgb(51, 51, 51);">:指在现在、将来控制</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">陕西启星汇申网络科技有限公司</span><span
|
||||
style="color: rgb(51, 51, 51);">、受</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">陕西启星汇申网络科技有限公司</span><span
|
||||
style="color: rgb(51, 51, 51);">控制或与</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">陕西启星汇申网络科技有限公司</span><span
|
||||
style="color: rgb(51, 51, 51);">处于共同控制下的公司、机构。</span></p>
|
||||
<p><strong>3、未成年人</strong><span style="color: rgb(51, 51, 51);">:指不满十八周岁的自然人。十六周岁以上的未成年人,以自己的劳动收入为主要生活来源的,视为完全民事行为能力人。</span>
|
||||
</p>
|
||||
<p><strong>4、儿童</strong><span style="color: rgb(51, 51, 51);">:指不满十四周岁的未成年人。</span>
|
||||
</p>
|
||||
<p><strong>(二)适用范围</strong></p>
|
||||
<p>
|
||||
<strong>本政策适用于羽声语音的产品或服务。如我们关联公司的产品或服务中使用了羽声语音直播提供的产品或服务,则本政策同样适用于该部分产品或服务。但请您注意,本政策不适用于以下情况:</strong>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">1、为我们的产品或服务提供广告服务的第三方的信息收集/处理做法;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、我们的产品或服务可能会包含或链接至第三方提供的信息与/或第三方服务(包括任何第三方应用、网站、产品、服务等),这些信息与/或服务由第三方负责运营,具体规则请参照该第三方的隐私政策或类似声明;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">3、其他非</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音</span><span
|
||||
style="color: rgb(51, 51, 51);">向您提供的产品与/或服务内容。</span></p>
|
||||
<p><strong>二、我们如何收集和使用您的个人信息</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">我们收集和使用的您的个人信息类型包括两种:第一种:我们产品与/或服务的基本业务功能所必需的信息:此类信息为产品与/或服务正常运行的必备信息,您须授权我们收集。如您拒绝提供,您将无法正常使用我们的产品与/或服务;第二种:拓展业务功能可能需要收集的信息:此信息为非基本业务功能所需的信息,您可以选择是否授权我们收集。如您拒绝提供,将导致拓展业务功能无法实现或无法达到我们拟达到的效果,但不影响您对基本业务功能的正常使用。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">我们在此特别提醒您:我们致力于打造多样的产品和服务以满足您的需求。因我们向您提供的产品和服务种类众多,且不同用户选择使用的具体产品/服务范围存在差异,故基本/拓展功能及对应收集使用的个人信息类型、范围等会有所区别,请以具体的产品/服务功能为准。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">我们收集和使用您的个人信息的场景有:</span></p>
|
||||
<p><strong>(一)注册成为我们的用户</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">当您在</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">上创建</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">账号时,您需要提供您</span><strong>本人的实名手机号码、验证码</strong><span
|
||||
style="color: rgb(51, 51, 51);">并完善相关的网络身份识别信息(包括</span><strong>头像、昵称、登录密码、性别、生日</strong><span
|
||||
style="color: rgb(51, 51, 51);">)。</span><strong>您需理解,手机号码、验证码匹配结果、性别、生日均属于您的敏感个人信息,我们收集您的手机号码、验证码是基于法律法规的相关要求。其中:(1)实名手机号码、验证码是为了验证您的身份,满足相关法律规定的网络实名制要求;(2)生日是为了协助判断您是否为年满十八周岁的成年人,若您是未成年人,我们将不对您提供服务,请您谅解,也提请您按真实情况填写相应信息,切勿虚构、假冒;(3)性别是为了向您提供性别匹配服务。上述敏感个人信息,您有权拒绝提供,但将无法使用相关功能或服务,请您谨慎考虑后再选择是否提供。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">在您注册账号后,您可以根据自身需求选择</span><strong>填写学校、个性签名、家乡、兴趣爱好等个人主页信息,来帮助您更加形象的展示自我</strong><span
|
||||
style="color: rgb(51, 51, 51);">。但如果您不提供这些信息,将不会影响本服务的基本业务功能。</span><strong>您在个人主页发布的上述信息、动态、添加的兴趣标签、游戏名片,以及你的账号等级、ID号、获赞数、粉丝数,将会在账号(包括APP和微信小程序)的个人主页中公开展</strong><span
|
||||
style="color: rgb(51, 51, 51);">示,您也可以通过APP设置-隐私进行信息隐藏(不对未关注用户显示可见)或通过第六节所述管理您的个人信息。</span>
|
||||
</p>
|
||||
<p><strong>(二)进行实名认证</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、为满足相关法律规定及监管要求、确保用户身份真实性、实现反欺诈等风控、保障系统与服务安全(包括依法保护未成年人合法权益、用户权益发放、打击电信网络诈骗等需要),当您使用</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">中某些特定类型的产品与/或服务,</span><strong>您需要向平台提供您本人的真实姓名及身份证号码信息(敏感个人信息),并可能需要通过您的人脸信息(敏感个人信息)进行身份一致性核验</strong><span
|
||||
style="color: rgb(51, 51, 51);">:</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(1)在您进行实名认证时,</span><strong>若您选择或产品页面进入火山引擎、腾讯云等第三方的实名认证程序(人脸识别功能),我们及/或第三方会申请、调用终端设备的摄像头权限来采集您的面部识别信息,在您授权后,前述第三方实名认证程序将通过SDK方式获取您的如下敏感个人信息:姓名、身份证件号码、人脸信息(指为验证或识别您的身份而采集的人脸图像、视频,以及基于上述图像、视频提取的面部识别特征),为了准确验证您的身份,第三方需将上述信息与其合法存有的(如基于法律法规或政府部门、有权机关授权或存储)您的个人信息进行比对核验。为了验证实名认证结果的有效性,并及时解决用户就实名认证结果的争议或投诉,您通过以上方式实名认证的,第三方会向我们返回人脸识别验证结果以及为验证或识别您的身份而采集的部分人脸图像、视频(具体以第三方提供为准,此为您的敏感个人信息),除此外,我们会存储您在上述实名认证过程中主动填写的姓名、身份证号码(敏感个人信息)。</strong>
|
||||
</p>
|
||||
<p><strong>当您通过本平台主动选择进行真人头像认证时,经您同意后,我们会收集您上传的头像照片,为了验证您上传的头像照片为您本人,不存在冒用或盗用他人照片、头像的情形,我们将请求您按上述方式通过第三方人脸识别程序完成实名认证,经第三方反馈验证一致的,您上传的头像照片将作为您在羽声语音直播APP内的头像进行公开,具体规则请见《真人头像认证协议》。因此,我们在此提醒您谨慎使用真人头像认证功能,您有权拒绝,且您拒绝不影响您继续使用本平台的基本业务功能。</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>具体使用的第三方人脸识别程序可通过第四节第(一)条所列《羽声语音直播与第三方共享个人信息清单》查阅。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(2)若您无法通过上述程序完成实名认证,您可以选择通过人工认证方式完成实名认证程序,为了完成实名认证服务,我们将依据相关法律法规获取并存储您的个人身份信息,包括如下:</span><strong>姓名(敏感个人信息)、身份证件类型(包括但不限于相应的身份证、护照、台湾居民来往大陆通行证、港澳居民往来内地通行证等)和相应的证件正反面图片(敏感个人信息)、您手持相应身份证件的照片(敏感个人信息)。</strong>
|
||||
</p>
|
||||
<p><strong>提请您特别注意,您的身份证件信息、您手持身份证件的照片、真人照片、人脸信息均属于敏感个人信息,您可以拒绝提供,如果拒绝提供您将可能无法获得需要实名认证的特定服务,但不影响您正常使用产品的基本业务功能(包括产品的浏览和观看功能);同时,我们将依法记录、保存验证身份信息及验证结果,这些信息仅供完成验证目的,或者其他法律法规所规定的用途,未经您明示授权不会用作其他目的。</strong>
|
||||
</p>
|
||||
<p><strong>2、具体实名场景及对应服务主要包括(具体以您使用的功能为准):</strong></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(1)当您申请注册为互联网发布者(主播)、开设个人房时,</span><strong>需要提供您的真实姓名、身份证件信息(敏感个人信息)进行实名身份认证,并通过您的面部识别信息(敏感个人信息)进行身份一致性核验</strong><span
|
||||
style="color: rgb(51, 51, 51);">。通过验证后,您方可在平台上从事直播发布活动。如果您拒绝提供上述信息(您有权拒绝),您将可能无法获得相关服务(开播或开设个人房间),但不影响您正常使用产品的浏览和观看功能。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(2)当您通过</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">进行充值、消费时(</span><strong>特别是当您使用下单功能时</strong><span
|
||||
style="color: rgb(51, 51, 51);">),为了保证您的资金安全,避免未成年人使用下单功能,我</span><strong>们可能需要您提供您的真实姓名、身份证件信息(敏感个人信息)进行实名身份认证,并可能需要您通过您的面部识别信息(敏感个人信息)进行身份一致性核验</strong><span
|
||||
style="color: rgb(51, 51, 51);">。前述信息您可以拒绝提供,您拒绝提供前述信息的,只会使您无法使用</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">对应功能,但不影响您使用其他功能。</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(3)当您使用提现功能,我</span><strong>们会需要您绑定银行卡账号信息、支付宝账号、身份证号码、姓名(敏感个人信息)进行实名认证。在您授权后,我们可能需要通过您的面部识别信息(敏感个人信息)进行身份一致性核验</strong><span
|
||||
style="color: rgb(51, 51, 51);">。您可以拒绝提供前述信息,但您拒绝提供将导致您无法使用对应功能,但不影响您使用</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">的其他功能。</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(4)在账号冻结、封禁申诉时,为了核实争议账号是您本人持有,平台还将使用您注册时使用的</span><strong>实名手机号码、身份证件信息(敏感个人信息)进行身份核实认证</strong><span
|
||||
style="color: rgb(51, 51, 51);">。</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(5)基于依法保护未成年人权益的需求,我们为未成年人提供了青少年模式,若您拟解除、退出青少年模式,我们会需要您提</span><strong>供真实姓名、身份证件信息(敏感个人信息),并在您授权后,我们可能需要通过您的面部识别信息进行身份一致性核验</strong><span
|
||||
style="color: rgb(51, 51, 51);">。如果您拒绝提供前述信息,您将无法退出青少年模式,但不影响您在青少年模式下使用</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">产品和服务。</span></p>
|
||||
<p><strong>(三)为您提供服务内容的浏览/播放/搜索/下载</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、</span><strong>当您进行直播间、聊天室、视频、音频等服务内容的浏览、播放、下载功能时,为与您的移动设备进行必要的适配,向您提供连续性、一致化的使用体验以及最优化的页面展示,我们需要收集您的设备信息、个人上网记录。</strong>
|
||||
</p>
|
||||
<p><strong>设备信息包括:浏览器类型、设备型号、操作系统版本、设备设置、DEVICEID、AndroidID、MAC地址、IMEI、IDFA、OAID、ICCID、UDID、UUID、MEID及其他设备标识符、设备环境。</strong>
|
||||
</p>
|
||||
<p><strong>个人上网记录包括:浏览/点击/播放记录、收藏/关注/预约记录、点赞/分享/发布记录等。</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">我们收集这些信息是为了向您提供直播间、视频、音频等内容的浏览、播放和展示服务,如您拒绝提供上述权限将可能导致您无法使用我们的相关产品与服务。请您理解,单独的设备信息、日志信息是无法识别特定自然人身份的信息。如果我们将这类非个人信息与其他信息结合用于识别特定自然人身份,或者将其与个人信息结合使用,则在结合使用期间,这类非个人信息将被视为个人信息,除取得您授权或法律法规另有规定外,我们会将该类个人信息做匿名化、去标识化处理。</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">2、当您使用我们提供的搜索功能时,我们还会收集您搜索的关</span><strong>键字信息、设备信息(包括设备型号、操作系统版本、设备设置、AndroidID、MAC地址、IMEI、IDFA、OAID、ICCID等设备标识符、设备环境)、日志信息(包括您的浏览记录和时间、您搜索的时间以及次数)</strong><span
|
||||
style="color: rgb(51, 51, 51);">。我们收集这些信息是为了方便您后续查找时无需再次输入,并向您快速匹配您所需要的内容以及您可能感兴趣的内容,为了提供高效的搜索服务,部分前述信息会暂时存储在您的本地存储设备之中,并可向您展示搜索结果内容、搜索历史记录。您可以自主删除前述搜索记录。搜索的关键词信息通常无法单独识别您的个人身份,不属于您的个人信息,不在本政策的限制范围内。但当您的搜索关键词信息与您的其他信息有联结并可识别您的个人身份时,在结合使用期间,我们会将您的搜索关键词信息作为您的个人信息,与您的搜索历史记录一同按照本政策对其进行处理与保护。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">当您分享/接收被分享的信息时,我们会在您进入</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">时访问您的剪切板,写入或读取其中包含的文字、链接、口令、分享码,以实现分享、跳转功能。我们不会收集、存储剪切板的其他信息。</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">3、当您使用下载功能时,经您同意后,我们会访问您的</span><strong>存储权限</strong><span
|
||||
style="color: rgb(51, 51, 51);">,以便在您设备外置存储空间内写入相关文件。如您拒绝提供,仅会使您无法使用该功能,但并不影响您正常使用产品或服务的其他功能。同时,您也可以随时通过您设备的相关功能设置开启/取消该权限。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(五)</span><strong>帮助您上传或发布图文、音频和视频</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、若您通过</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">的社区功能或通过</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">的评论、分享、发帖、发布动态等功能上传/发布/编辑图文、音频、视频时,当您使用到具体功能时,我们将向您分别单独请求</span><strong>访问您设备的相机/摄像头权限、相册权限(IOS端)/存储权限(安卓端)、录音/麦克风权限:(1)经您同意授权相机/摄像头权限后,我们会访问您的相应权限,以便您拍摄照片、视频,并采集、识别上述功能实现过程中所拍摄或录制的图片及视频信息</strong><span
|
||||
style="color: rgb(51, 51, 51);">;</span><strong>(2)经您同意授权相册权限(IOS端)/存储权限(安卓端)后,我们会访问您的相应权限,以便您查看、选择相册里的图片/视频发布动态、反馈意见,设置与更换头像、封面,聊天时分享图片/视频,以及保存图片/视频至相册,您还可以在其他场景访问设备里的照片、音频和视频,以及保存内容到设备;(3)经您同意授权录音/麦克风权限后,我们会访问您的相应权限,以便识别您上传的语音信息,并采集、识别上述功能实现过程中所录制、输入的音频信息。如您拒绝提供上述权限的仅会使您无法使用该功能,但并不影响您正常使用产品/服务的其他功能,同时,您也可以随时通过您的设备系统或使用我们的产品/服务的相关功能设置页面开启/取消该权限。</strong>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">2、如您自愿填写信息或自愿发布内容的,我们会收集您上传的</span><strong>视频、照片、音视频、帖子、评论、点赞、关注、分享信息、浏览及搜索信</strong><span
|
||||
style="color: rgb(51, 51, 51);">息。您可随时删除您发布的照片、音视频、帖子及评论内容。为了验证您发布内容的合法合规性,避免您发布的内容涉及违法或侵犯第三方合法权益的情形。您</span><strong>同意我们为了上述目的将您发布的图文、音频、视频内容提供给我们的服务提供商,并由我们的服务提供商对上述内容进行审核、标注后向我们反馈结果。</strong><span
|
||||
style="color: rgb(51, 51, 51);">我们不会向上述服务商传输或共享您的个人信息,我们仅会对您发布内容的合法合规性进行审核。</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">3、当您使用设备相机扫描二维码时,我们将访问您设备的</span><strong>相机/摄像头权限</strong><span
|
||||
style="color: rgb(51, 51, 51);">。如您拒绝提供的仅会使您无法使用该功能,但并不影响您正常使用产品与/或服务的其他功能。同时,您也可以随时通过您的设备的设置开启/取消该权限。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">4、您在使用动态发布等功能时发布的公开信息可能涉及您或他人的个人信息或个人隐私信息,如您在分享、评论时选择上传的包括个人信息的图片或视频。</span><strong>您应更为谨慎考虑是否公开该等信息,以及获得合法权利人授权后再行发布,同时如该等信息中涉及未成年人个人信息的,您应在发布前征得其监护人同意。</strong>
|
||||
</p>
|
||||
<p><strong>(六)录制音视频及提供直播功能</strong></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">当您使用录制音视频、使用个人房间服务以及直播服务时,经您分别授权我们将</span><strong>访问您设备的相机/摄像头权限(当您同意开启此项权限后,我们会使用您设备上的相机拍摄功能。此项功能将用于实现照片拍摄、录制视频功能,并采集、识别上述功能实现过程中所拍摄或录制的图片及视频信息)、录音(麦克风)相关权限(当您同意开启此项权限后,我们会使用您设备上的麦克风功能,并会识别您上传的语音信息。此项权限将用于实现语音输入功能,并采集、识别上述功能实现过程中所输入的语音信息)</strong><span
|
||||
style="color: rgb(51, 51, 51);">,如您拒绝授权的仅会使您无法使用该功能,但并不影响您正常使用产品与/或服务的其他功能。同时,您也可以随时通过您的设备设置开启/取消该权限。此外,</span><strong>为保证您使用直播或聊天室功能时的流畅度、节省您的流量,我们会收集您使用该功能时段内使用流量的大小。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(七)消费与提现</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">当您通过</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音</span><span
|
||||
style="color: rgb(51, 51, 51);">购买商品和/或服务时(如SVIP会员购买、购买虚拟商品、个性装扮、礼物),为帮助您完成交易、保障交易安全、提供订单查询、客服及售后服务,</span><strong>我们需要根据商品的类型收集如下部分或全部的订单信息:下单时间、订单编号、订单状态、交易的商品信息、支付信息(支付金额、支付方式、支付流水号、支付状态、第三方支付渠道的支付账号,敏感个人信息)、虚拟商品消费使用记录、会员开通时间</strong><span
|
||||
style="color: rgb(51, 51, 51);">。为此,为保障您的账户和资金安全以及支付服务的安全稳定运行、履行反电信网络诈骗等法定义务,我们还会收集您必要的设备信息(IP地址)并提供给您选择的第三方支付渠道。为向您提供售后与争议解决服务之目的,我们需要及时获悉并确认交付、售后的进度及状态,您同意我们可自相应第三方处收集与交付、售后进度相关的信息。我们向您承诺,我们会以最大努力保障您的个人信息安全,并严格要求第三方对您的个人信息保密,只以交付、售后之目的获悉和使用,不得对外泄露或做其他任何用途。您可以拒绝提供前述信息,但您拒绝提供将导致您无法使用对应功能,但不影响您使用</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">的基本业务功能。</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">当您使用提现功能时,</span><strong>为了完成支付结算,我们会收集、使用您主动填写的收款账户信息(银行卡账号信息及开户行信息、支付宝账号及/或微信账号,具体以您填写为准)以及身份证号码、姓名,并会共享给第三方支付结算机构(请见第四节第(一)项)。前述信息为敏感个人信息,您可以拒绝提供,您拒绝提供将导致您无法使用对应提现功能,但不影响您使用羽声语音直播的其他功能。</strong>
|
||||
</p>
|
||||
<p><strong>(八)客户服务</strong></p>
|
||||
<p><strong>当您主动填写羽声语音APP上的反馈意见(如帮助与反馈-意见反馈页面)、举报投诉页面时,我们会收集您主动填写的手机号、反馈/举报投诉内容(请谨慎考虑后再决定是否填写),我们收集信息仅用于收集您的意见,便于与您联系、尽快帮助您解决问题。</strong>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">当您向我们发起投诉、申诉或进行咨询时,为了保障您的账户及系统安全,</span><strong>我们需要您提供必要的个人信息(包括账号信息、姓名、手机号、身份证以及其他必要身份信息)以核验您的用户身份</strong><span
|
||||
style="color: rgb(51, 51, 51);">。为</span><strong>便于与您联系、尽快帮助您解决问题或记录相关问题的处理方案及结果,我们可能会收集您与我们的沟通信息(包括文字/图片/音视频/通话记录形式)、您为了证明相关事实提供的信息、与客服需求相关联的其他必要信息。如您针对具体的订单发起客服需求的,我们还会使用您的订单信息。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">以上信息为您的</span><strong>个人敏感信息</strong><span
|
||||
style="color: rgb(51, 51, 51);">,您有权拒绝提供,但我们收集这些信息是为了调查事实与帮助您解决问题,如您拒绝提供上述信息,我们可能无法向您及时反馈投诉、申诉或咨询结果。</span>
|
||||
</p>
|
||||
<p><strong>(九)为您提供安全保障服务</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">为了使</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">产品及服务与您的移动设备进行必要的适配,提高您使用我们及我们合作伙伴提供服务的安全性,保护您或其他用户或公众的人身财产安全免受侵害,更好的预防钓鱼网站、欺诈、网络漏洞、计算机病毒、网络攻击、网络入侵等安全风险,分析当前设备的风险等级,有效识别各种作弊行为、风险设备、恶意刷量、恶意程序、保护您的账号安全,我们会收集为实现安全保障功能的必要信息,我们会获取您的以下信息:</span>
|
||||
</p>
|
||||
<p><strong>1、网络访问日志信息和用户日志信息。包括:网络信息(如网络类型)、运营商信息(如SIM卡信息)、账号信息(如账号登录地)以及使用“羽声语音直播”产品或服务的频率、崩溃数据、总体安装、使用情况、性能数据、服务故障等信息。</strong>
|
||||
</p>
|
||||
<p><strong>2、您的设备信息。包括:设备型号、操作系统、设备序列号/SN、设备标识符(如IMEI/IMSI/Android
|
||||
ID/IDFA/OpenUDID/GUID/ICCID/
|
||||
UUID/MEID/DEVICEID)、设备MAC地址、应用列表、登陆IP地址、软件版本号、接入网络的方式、类型和状态、设备当前运行进程/运行中进程信息、设备传感器信息、蓝牙信息屏幕尺寸等参数信息,同时为了保证您的账号安全,我们会检测您设备的root状态</strong><span
|
||||
style="color: rgb(51, 51, 51);">。请您注意,为了便于您及时接收、发送聊天消息、接收消息通知,我们会在后台状态下获取您设备的MAC地址。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">我们可能会使用或整合您的上述日志信息与设备信息、账户信息、交易信息、支付信息以及其他取得您授权或依据法律共享的信息,综合判断您账户及交易风险、完成身份验证、检测,防范安全事件,并依法采取必要的记录、审计、分析、处置措施,保护各方合法权益稳定不受侵害。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">您理解并同意,为了帮助我们进行bug分析、反作弊、反黑产等安全保护工作,保障您正常使用本产品与/或服务、保障您的账号安全,</span><strong>在您的羽声语音App每次切换至后台或处于静默状态下或重新启动时,我们会收集您的Mac地址信息(包括手机Mac地址和蓝牙Mac地址)、IMEI、获取运行中进程信息、设备序列号、Android
|
||||
ID、DEVICEID,我们将把读取频次控制在合理范围内。</strong></p>
|
||||
<p><strong>请您理解,单独的设备信息、日志信息等是无法识别特定自然人身份的信息。如果我们将这类非个人信息与其他信息结合用于识别特定自然人身份,或者将其与个人信息结合使用,则在结合使用期间,这类非个人信息将被视为个人信息,除取得您授权或法律法规另有规定外,我们会将该类个人信息做匿名化、去标识化处理。</strong>
|
||||
</p>
|
||||
<p><strong>同时,为了维护网络安全、保障良好生态,便于公众为公共利益实施监督,依据《互联网用户账号信息管理规定》等法律规定,您的IP地址所对应的归属地域信息将会展示在您的个人资料页。境内展示到省(区、市),境外展示到国家或地区,信息以网络运营商数据为准,请您理解,该信息不会泄露您的详细地址,相关展示暂不支持手动开启或关闭。</strong>
|
||||
</p>
|
||||
<p><strong>(十)我们获取的设备权限</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">为确保相关业务功能的正常实现,我们需要根据具体的使用场景调用对应的必要权限。请您注意,您开启任一权限即代表您授权我们可以收集和使用相关个人信息来为您提供对应服务,若您关闭任一权限或取消授权,我们将不再基于对应权限继续收集和使用相关个人信息,也无法为您提供该权限所对应的服务。但是,您关闭权限的决定不会影响此前基于您的授权所进行的信息收集及使用。</span>
|
||||
</p>
|
||||
<p><strong>(十一)收集和使用个人信息的其他规则</strong></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">1、若您提供的信息中含有其他用户的个人信息,在向我们提供这些个人信息之前,您需确保您已经取得合法的授权。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、您理解并知悉,您向外部第三方(</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">关联公司不在此限)</span><strong>提供的个人信息,或外部第三方收集的您的个人信息,我们无法获取,更不会使用非常规方式(如:恶意干预对方系列APP数据)擅自以软件程序获得您的个人信息。羽声语音直播可能因业务发展的需要而确实需要从第三方间接收集(如共享等)您的个人信息的,且由我们直接或共同为您提供产品或服务的,我们会在收集前明确以书面形式要求该第三方说明其个人信息来源,以及是否已经就其收集、处理以及向我们提供您的个人信息取得了您的合法授权(如果使用方式和范围超出您在第三方原授权范围的,我们会再次征得您的授权同意)。我们的某些产品或服务由第三方业务合作伙伴提供或共同提供时,为了必要且合理的开展业务,我们可能会从部分业务合作伙伴处间接收集的您的部分信息、其他方使用我们的产品/服务时所提供有关您的信息。如果第三方的授权范围无法涵盖我们的处理和使用目的时,我们会自行或者要求该第三方征得您的同意后再行处理您的个人信息。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">3、如果某一需要收集您的个人信息的产品/服务未能在本隐私政策中予以说明的,或者我们超出了与收集您的个人信息时所声称的目的及具有直接或合理关联范围的,我</span><strong>们将在收集和使用您的个人信息前,通过更新本隐私政策、页面提示、弹窗、站内信、网站公告或其他便于您获知的方式另行向您说明,并为您提供自主选择同意的方式,且在征得您明示同意后收集和使用。</strong>
|
||||
</p>
|
||||
<p><strong>4、征得授权同意的例外</strong></p>
|
||||
<p><strong>您理解并同意,在以下情况下,我们无需取得您的授权同意即可收集和使用您的个人信息:</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(1)与国家安全、国防安全有关的;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(2)与公共安全、公共卫生、重大公共利益有关的;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(3)与犯罪侦查、起诉、审判和判决执行等有关的;</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(4)出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到您本人同意的;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(5)所收集的个人信息是您自行向社会公众公开的;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(6)从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道,并依照《个人信息保护法》规定在合理的范围内处理您自行公开或者其他已经合法公开的个人信息;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(7)根据您的要求签订合同所必需的;</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(8)用于维护所提供的产品或服务的安全稳定运行所必需的,例如发现、处置产品或服务的故障;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(9)为合法的新闻报道所必需的;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(10)学术研究机构基于公共利益开展统计或学术研究所必要,且对外提供学术研究或描述的结果时,对结果中所包含的个人信息进行去标识化处理的;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(11)法律法规规定的其他情形。</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">我们需要特别提醒您的是:</span><strong>由于我们的产品和服务较多,为您提供的内容也不同,因此收集的您的个人信息也会因产品/服务的内容不同而有所区别,具体以产品/服务实际提供为准。我们可能会不时推出新的或优化后的功能,或者依据最新法律法规要求,可能需要收集、使用您的新的个人信息或变更个人信息使用目的或方式。届时,我们将通过更新本政策、弹窗、页面提示等方式另行向您说明并为您提供自主选择同意的方式,且在征得您同意后再收集、使用。</strong>
|
||||
</p>
|
||||
<p><strong>三、我们如何使用Cookie和第三方H5页面</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">为使您获得更轻松的访问体验,您使用</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">产品或服务时,我们可能会通过采用各种技术收集和存储您访问</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">服务的相关数据,在您访问或再次访问</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">服务时,我们能识别您的身份,并通过分析数据为您提供更好更多的服务。包括使用小型数据文件识别您的身份,这么做是为了解您的使用习惯,帮您省去重复输入账户信息的步骤,或者帮助判断您的账户安全。这</span><strong>些数据文件可能是Cookie、Flash
|
||||
Cookie,或您的浏览器或关联应用程序提供的其他本地存储(统称“Cookie”)。</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">网页上常会包含一些电子图像,称为“单像素GIF文件”或“网络beacon”,它可以帮助网站计算浏览网页的用户或访问某些cookie。我们会通过网络beacon收集您浏览网页活动信息,例如您访问的页面地址、您先前访问的援引页面的位址、您停留在页面的时间、您的浏览环境以及显示设定等。</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">如果您的浏览器或浏览器附加服务允许,您可以修改对Cookie的接受程度或者拒绝</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">的Cookie(如:在浏览器具备该功能的前提下,可以通过您的浏览器的设置以管理、部分或全部拒绝Cookie与/或同类技术;或删除已经储存在您的计算机、移动设备或其他装置内的Cookie与/或同类技术,从而实现我们无法全部或部分追踪您的个人信息。您如需详细了解如何更改浏览器设置,请具体查看您使用的浏览器的相关设置页面),但拒绝</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">的Cookie可能无法使用由我们提供的、依赖于Cookie的功能或服务(如有)。</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">第三方H5页面。为了提升服务便捷性、方便用户快速触达第三方服务,我们可能会接入</span><strong>第三方的H5服务页面入口,如果您进入这些H5页面,该第三方可能会收集你的手机号、身份证件号、付款账号信息,请注意,您在以上第三方H5页面进行的各项操作请遵守该等第三方的隐私保护政策。当您离开我们平台跳转至第三方H5页面时,我们提醒您注意保护个人隐私。本平台不收集、不存储您在该类第三方服务页面填写和提交的任何个人信息。</strong>
|
||||
</p>
|
||||
<p><strong>四、我们如何共享、转让、公开披露您的个人信息</strong></p>
|
||||
<p><strong>(一)共享</strong></p>
|
||||
<p>
|
||||
<strong>我们不会与陕西启星汇申网络科技有限公司及关联方以外的任何公司、组织和个人分享您的个人信息,但以下情况除外:</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、获得您(及监护人)明确同意或授权的共享;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、基于法定情形提供。根据法律法规的规定、诉讼争议解决需要、您与我们签署的相关协议(包括在线签署的电子协议及平台规则)或法律文件,或行政、司法等有权机关依法提出要求时,我们可能会共享您的个人信息;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">3、提供统一管理服务。为</span><strong>便于您统一管理账号,体验更优质的服务,我们可能会向我们的关联公司共享您的个人信息。但我们只会共享必要的个人信息,如果我们共享您的个人敏感信息或者关联方改变个人信息的使用目的,将再次征求您的授权同意;</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">4、提供必要的合作服务并保证服务安全、优化。</span><strong>我们提供的产品/服务大多是无法单独完成的,故我们的某些服务将由业务合作伙伴提供。为保障为您提供的服务顺利完成,我们可能会将您的个人信息共享给我们的合作伙伴,包括基础技术服务、支付服务、营销活动等的合作商、第三方商家、广告商等;同时,为了向您提供更完善、优质、安全的产品和服务,我们的应用中会嵌入授权合作伙伴的软件工具开发包(本政策中简称“SDK”)或其他类似的应用程序,我们的某些服务将由授权合作伙伴提供或使用第三方SDK相关技术为您提供服务。基于此,我们会与合作伙伴共享您的某些个人信息,或者第三方SDK会通过SDK方式收集您的个人信息</strong><span
|
||||
style="color: rgb(51, 51, 51);">,具体包括:</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(1)</span><strong>第三方账号登录、内容分享</strong><span
|
||||
style="color: rgb(51, 51, 51);">。QQ、微信、新浪微博会通过SDK方式收集您的</span><strong>位置信息、网络信息(包括Wi-Fi信息)、设备标识信息(MAC地址、IMEI、IMSI)、运营商信息、外部存储设备信息,用于实现第三方账号授权登录、共享发布的内容及评论等信息。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(2)</span><strong>安全监测与风险防范</strong><span
|
||||
style="color: rgb(51, 51, 51);">。为了保障您的账号安全,避免您遭受欺诈、网络病毒、网络攻击等风险,为我们提供安全保障的合作伙伴会通过SDK方式收集与您有关的必要</span><strong>设备信息、日志信息,以及您的使用习惯和常用软件信息等来综合判断您的账号及交易风险,预防安全事件的发生。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(3)</span><strong>支付与结算功能。</strong><span
|
||||
style="color: rgb(51, 51, 51);">支付功能由与我们合作的第三方支付机构向您提供服务,基于此,支付宝、微信、银联会通过SDK方式收集您的</span><strong>手机号、设备信息识别码(包括IMSI)、位置信息、网络信息(包括Wi-Fi信息)、当前运行进程/获取运行中进程信息、屏幕参数、运营商信息</strong><span
|
||||
style="color: rgb(51, 51, 51);">,保证充值、消费、支付功能的正常使用,这些信息是支付功能所必需的信息,拒绝提供将导致您无法使用该功能。</span><strong>当您提现收入(如有)时,为了您能及时完成收入的结算与提现、依据法律规定完成税费缴纳,将由与您另行单独确认的第三方服务方向您提供结算、税费扣缴服务,基于此,我们会向该类第三方服务方共享您提现时主动提供的收款账户信息以及身份信息,具体信息详见第二节第(七)款。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(4)人脸识别。阿里云、腾讯云、字节跳动会通过SDK方式收集您的证件信息、设备标识信息、网络信息(包括Wi-Fi信息)、设备传感器信息、屏幕参数、应用列表,该等第三方获取的面部特征信息用于人脸核验,我们只获得核验结果,不保存您的面部特征信息。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(5)直播视频服务。声网、会</span><strong>通过SDK收集您的共享Wi-Fi信息、设备标识信息、地理位置信息、运营商信息、外部存储设备、当前运行进程/获取运行中进程信息、屏幕参数,并共享用户授予的读取/写入外置存储、位置权限、获取设备信息、相机/摄像头权限、读取手机/电话状态,用于聊天室内和IM音视频通话,图片上传、直播推流和直播回放功能等相关功能。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">目前,我们接入的第三方服务商主要包括以下几种类型:</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">用于消息推送功能,包括手机厂商Push推送、特定事件提醒;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">用于支付相关服务,包括订单支付、交易行为核验、收入结算、支付信息汇总统计;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">用于在您同意的情况下获取设备位置权限、搜集设备信息和日志信息;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">用于第三方授权服务,包括第三方账号登陆、将有关内容分享至第三方产品;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">用于优化产品性能,包括提高硬件配网能力、降低服务器成本、功能热修复;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">用于账号安全、产品加固相关服务,包括网络监测、域名解析、防劫持、防黑产、反作弊、加解密服务。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">我们接入的部分第三方SDK可能会收集您的个人信息,如您在我们的服务中使用这类由第三方提供的服务时,您同意将由其直接收集和处理您的信息。我们会评估这类第三方服务收集个人信息的合法性、正当性、必要性,要求该等第三方对您的个人信息采取保护措施,并严格遵守相关法律法规与监管要求。您可以查看下方《语音接入第三方SDK目录》,了解我们主要接入的第三方SDK基本情况。</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">羽声语音直播接入第三方 SDK 目录(与全国平台登记信息完全一致)</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">1、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:APP 支付客户端 SDK<br>开发者信息:支付宝(杭州)信息技术有限公司<br>服务类型:唤起支付宝 App 完成支付<br>所涉信息:设备 MAC 地址、网络访问、WiFi 状态、读取电话状态、写入外部存储<br>隐私政策链接:</span>https://opendocs.alipay.com/open/54/01g6qm
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">2、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:QQ 互联 SDK(QQ 开放平台)<br>开发者信息:深圳市腾讯计算机系统有限公司<br>服务类型:QQ 分享、授权登录<br>所涉信息:设备标识信息(IMEI/AndroidID/ICCID)、定位信息、地理位置、ANDROID_ID<br>隐私政策链接:</span>https://connect.qq.com/index.html
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">3、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:微信 OpenSDK Android<br>开发者信息:深圳市腾讯计算机系统有限公司<br>服务类型:微信分享、微信登录、微信支付、微信客服<br>所涉信息:设备标识信息(IMEI/AndroidID/ICCID)、定位信息、地理位置、ANDROID_ID<br>隐私政策链接:</span>https://support.weixin.qq.com/cgi-bin/mmsupportacctnodeweb-bin/pages/RYiYJkLOrQwu0nb8
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">4、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:声网音视频 SDK(含音频 RTC)<br>开发者信息:上海声网科技有限公司<br>服务类型:提供实时音频服务<br>所涉信息:设备 MAC 地址、IP 地址、网络访问、WiFi 状态、设备信息、文件存储权限、麦克风权限<br>隐私政策链接:</span>https://www.shengwang.cn/SDK-privacy-policy/
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">5、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:腾讯云即时通信 IM SDK<br>开发者信息:腾讯云计算(北京)有限责任公司<br>服务类型:即时通信(私聊、群聊、房间内公屏聊天)<br>所涉信息:设备 MAC 地址、IP 地址、网络状态、文件存储权限、麦克风权限、相机权限<br>隐私政策链接:</span>https://cloud.tencent.com/document/product/269/58094
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">6、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:ShareSDK(含友盟统计 / 友盟推送)<br>开发者信息:广州掌淘网络科技有限公司(ShareSDK)<br>服务类型:社会化分享、统计分析、消息推送<br>所涉信息:设备标识符(IMEI/Mac/android ID/IDFA/OPENUDID/GUID、SIM 卡 IMSI 信息)、社交账号公开信息、地理位置、IP 地址、应用列表<br>隐私政策链接:</span>https://www.umeng.com/page/policy
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">7、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:Bugly Android<br>开发者信息:深圳市腾讯计算机系统有限公司<br>服务类型:定位崩溃、异常上报与运营统计<br>所涉信息:日志信息(自定义日志、Logcat 日志、崩溃堆栈)、设备 ID(androidid / idfv)、联网信息、系统名称、系统版本、国家码<br>隐私政策链接:</span>https://privacy.qq.com/document/preview/fc748b3d96224fdb825ea79e132c1a56
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">8、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:腾讯云慧眼人脸核身增强版 SDK<br>开发者信息:腾讯云计算(北京)有限责任公司<br>服务类型:实名认证<br>所涉信息:个人身份信息(真实姓名、身份证号)、面部识别特征、读取短信、联系人、通话记录、位置信息、设备标识信息(IMEI、IMSI、AndroidID)<br>隐私政策链接:</span>https://cloud.tencent.com/document/product/1007/66043
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">9、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:音视频通话 TRTC SDK(Android)<br>开发者信息:深圳市腾讯计算机系统有限公司<br>服务类型:即时语音通话(私聊、群聊、房间内公屏聊天)<br>所涉信息:设备 MAC 地址、IP 地址、网络状态、文件存储权限、麦克风权限、相机权限<br>隐私政策链接:</span>https://cloud.tencent.com/document/product/647/57574
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">10、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:号码认证-android(阿里云一键登录)<br>开发者信息:阿里巴巴云计算(北京)有限公司<br>服务类型:手机号一键登录<br>所涉信息:网络类型、设备信息(IP 地址、设备制造商、设备型号、手机操作系统、SIM 卡状态)、运营商类型、本机号码<br>隐私政策链接:</span>https://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud202112211045_86198.html
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">11、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:对象存储 OSS Android SDK(阿里云)<br>开发者信息:阿里云计算有限公司<br>服务类型:平台图片、视频、礼物等文件存储<br>所涉信息:设备型号、设备操作系统信息(用于兼容性适配与故障排查)<br>隐私政策链接:</span>https://terms.alicdn.com/legal-agreement/terms/privacy_policy_full/20240202100310511/20240202100310511.html
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><span style="color: rgb(51, 51, 51); font-family: 宋体;">12、</span><span
|
||||
style="color: rgb(51, 51, 51);">SDK 名称:腾讯云 COS 文件存储器 SDK<br>开发者信息:腾讯云计算(北京)有限责任公司<br>服务类型:平台图片、视频、礼物等文件存储<br>所涉信息:设备型号、设备操作系统、IP 地址、网络连接类型(用于兼容性与传输优化)<br>隐私政策链接:</span>https://cloud.tencent.com/document/product/454/61839
|
||||
</p>
|
||||
<p><br></p>
|
||||
<p>13、<span
|
||||
style="color: rgba(0, 0, 0, 0.9); background-color: rgb(255, 255, 255); font-size: 16px;">SDK 名称:联通认证 SDK<br>开发者信息:联通在线信息科技有限公司<br>服务类型:手机号一键登录 / 本机号码校验<br>所涉信息:网络类型、网络地址(IP 地址)、运营商类型、本机手机号、手机设备类型、手机操作系统、硬件厂商<br>隐私政策链接:</span><a
|
||||
href="https://msv6.wosms.cn/html/oauth/protocol2.html" target="_blank"
|
||||
style="text-align: start;">https://msv6.wosms.cn/html/oauth/protocol2.html</a><br></p>
|
||||
<h3 style="text-align: start;">手机 GPS 定位说明(无第三方 SDK)</h3>
|
||||
<p>功能场景</p>
|
||||
<ol>
|
||||
<li style="text-align: start;">
|
||||
业务功能:判断主播/观众实时地理位置,用于「附近频道」「同城房间」「地区排行榜」「内容合规(区域管制)」等。
|
||||
</li>
|
||||
<li style="text-align: start;">
|
||||
触发时机:仅当用户首次进入需定位的页面时弹窗申请,拒绝不影响基础功能。
|
||||
</li>
|
||||
<li style="text-align: start;">所涉信息<br>精确位置(GPS 经纬度)、粗略位置(网络定位辅助)、手机方向传感器(用于地图罗盘旋转)。
|
||||
</li>
|
||||
<li style="text-align: start;">使用方式</li>
|
||||
</ol>
|
||||
<ul>
|
||||
<li style="text-align: start;">仅 App 前端调用
|
||||
Android「LocationManager」/iOS「CLLocationManager」系统接口,未集成任何第三方定位 SDK。
|
||||
</li>
|
||||
<li style="text-align: start;">
|
||||
定位结果仅在客户端内存临时使用,退出相关页面立即释放,不做后台持续采集、不上传服务器、不存储本地、不与任何第三方共享。
|
||||
</li>
|
||||
<li style="text-align: start;">权限管理<br>用户可随时在系统设置-应用权限-位置信息中关闭授权,关闭后涉及位置的功能将提示「需要位置权限」并引导重新开启。
|
||||
</li>
|
||||
<li style="text-align: start;">未成年人<br>如用户未满 14 周岁,我们将在征得监护人同意后才会申请位置权限,否则默认关闭定位相关功能。
|
||||
</li>
|
||||
</ul>
|
||||
<p><span style="color: rgb(51, 51, 51);"> </span></p>
|
||||
<p><strong>自启动和关联启动说明:</strong></p>
|
||||
<p><strong>为确保本应用处于关闭或后台运行状态下可正常接收到客户端推送的广播信息,本应用须使用(自启动)能力,将存在一定频率通过系统发送广播唤醒本应用自启动或关联启动行为,是因实现功能及服务所必要的。</strong>
|
||||
</p>
|
||||
<p><strong>请您知悉:(1)我们仅会出于合法、正当、必要、明确的目的共享您的个人信息,并且授权合作伙伴只能接触到其履行职责所需信息。同时,我们会与合作伙伴签署严格的保密协定,要求他们按照我们的说明、本政策以及其他任何相关的保密和安全措施来处理您的个人信息;(2)前述第三方合作伙伴为数据控制者,以其自己的名义获得您的同意以处理您的个人信息。合作方可能有其独立的隐私政策,我们建议您认真阅读并遵守第三方的隐私政策。如果您拒绝我们的合作方在提供服务时收集为提供服务所必需的个人信息,将可能导致您无法使用相应服务。</strong>
|
||||
</p>
|
||||
<p><strong>(二)转让</strong></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">我们不会将您的个人隐私信息转让给任何公司组织和个人,但以下情况除外:</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">1、在获取明确同意的情况下共享:获得您的明确同意后,我们将与其分享您的个人隐私信息;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、在涉及合并、收购、资产转让、破产清算时,你的个人信息有可能因此而被转移,如涉及个人隐私信息转让,我们将要求受让方继续受此政策约束并告知您受让方身份、联系方式,否则我们将要求受让方向您重新索取授权同意。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(三)公开披露</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">1、公开披露是指向社会或不特定人群发布信息的行为。我们仅在下列情形下,公开披露您的个人隐私信息:</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(1)征得您明确的授权同意;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(2)基于国家法律法规的规定而对外披露;</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(3)应国家司法机关及其他有关机关基于法定程序的要求而披露;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(4)为公共利益实施新闻报道、舆论监督等行为在合理的范围内公开的;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(5)为应对突发公共卫生事件,或在紧急情况下,为保护其他用户及第三方生命健康和财产安全而必须披露的,在该情况下我们将在紧急情况消除后及时告知您;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(6)应用户监护人合法要求而提供用户个人身份信息时;</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(7)对违规账号、欺诈行为等进行处罚公告、公布中奖/获胜者等名单时脱敏展示相关信息等必要事宜而进行的必要披露。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、对于公开披露的您的个人信息,我们会在收到公开披露申请后第一时间且审慎审查其正当性、合理性、合法性,并在公开披露时和公开披露后采取最严格个人信息安全保护措施和手段对其进行保护。</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(四)共享、转让、公开披露个人信息时事先征得授权同意的例外</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">下述情形中,共享、转让、公开披露您的个人信息无需事先征得您的授权同意:</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、与国家安全、国防安全直接相关的;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、与公共安全、公共卫生、重大公共利益直接相关的;</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">3、与犯罪侦查、起诉、审判和判决执行等直接相关的;或根据法律法规的要求、行政机关或公检法等有权机关的要求的;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">4、出于维护您或其他个人的生命、财产等重大合法权益但又很难得到您本人同意的;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">5、个人信息是您自行向社会公开的或者是从合法公开的渠道(如合法的新闻报道、政府信息公开等渠道)中收集到的;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">6、根据与您签订和履行相关协议或其他书面文件所必需的;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">7、法律法规等规定的其他情形。</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">请知悉,根据适用的法律,若我们对个人信息采取技术措施和其他必要措施进行处理,使得数据接收方无法重新识别特定个人且不能复原,则此类处理后数据的共享、转让、公开披露无需另行向您通知并征得您的同意。</span>
|
||||
</p>
|
||||
<p><strong>五、我们如何存储和保护您的个人信息</strong></p>
|
||||
<p><strong>(一)个人信息的存储</strong></p>
|
||||
<p><strong>1、存储地点</strong><span style="color: rgb(51, 51, 51);">:我们会按照法律法规规定,将境内收集的用户个人信息存储于中华人民共和国境内。目前我们不会跨境传输或存储您的个人信息或向境外提供个人信息的场景。将来如需跨境传输或存储的,我们会单独向您明确告知信息出境的目的、接收方、使用方式和范围、安全保证措施等情况并征得您的同意。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、</span><strong>存储期限:除非依据法律法规或双方约定,我们只会在为实现服务目的所必需的最短时间内留存您的个人信息,此外,我们或对您的相关信息保存至相关法律所规定的必要期限(例如,根据《电子商务法》规定:商品和服务信息、交易信息保存时间自交易完成之日起不少于三年;根据《网络安全法》规定:采取监测、记录网络运行状态、网络安全事件的技术措施,并按照规定留存相关的网络日志不少于六个月;根据《互联网用户公众账号信息服务管理规定》:互联网用户公众账号信息服务提供者应当记录互联网用户公众账号信息服务使用者发布内容和日志信息,并按规定留存不少于六个月)。</strong>
|
||||
</p>
|
||||
<p><strong>我们在判断前述期限的标准主要包括并以其中较长者为准:</strong></p>
|
||||
<p><strong>A. 完成与您相关的服务目的、维护相应服务及业务记录、应对您可能的查询或投诉;</strong></p>
|
||||
<p><strong>B. 保证我们为您提供服务的安全和质量;</strong></p>
|
||||
<p><strong>C. 您是否同意更长的留存期限;</strong></p>
|
||||
<p><strong>D. 是否存在保留期限的其他特别约定。</strong></p>
|
||||
<p>
|
||||
<strong>在超出保存期限后,我们会根据适用法律的要求删除或者匿名化处理您的个人信息,但法律有特殊要求的除外。</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>当我们的产品或服务发生停止运营的情况时,我们将以推送通知、公告等形式通知您,并在合理期限内删除您的个人信息或进行匿名化处理,法律法规另有规定的除外。</strong>
|
||||
</p>
|
||||
<p><strong>(二)个人信息的保护措施</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">数据传输方面,采用传输层安全协议等密码技术,通过Https等方式防止传输链路被嗅探、窃听截取风险,建立安全的隐私数据采集环境,保证数据采集的私密性和完整性。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">数据存储方面,我们会通过安全的方式存储您的信息,包括本地存储(例如利用APP进行数据缓存)。我们只会在为实现服务目的所必需的时间内或法律法规规定的条件下存储您的个人信息。您可以自主选择删除观看历史、视频缓存、搜索记录等您在使用</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音</span><span
|
||||
style="color: rgb(51, 51, 51);">APP服务时提供和产生的数据记录。</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">信息安全方面,我们努力为您的信息安全提供保障,以防止信息的泄露、丢失、不当使用、未经授权访问和披露等。我们使用多方位的安全保护措施,以确保您的个人信息保护处于合理的安全水平,包括技术保护手段、管理制度控制、安全体系保障等诸多方面。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">数据访问和使用的安全控制方面,实施严格的数据权限控制机制,采取多重身份认证技术,并对能够处理您的信息的行为进行监控,避免数据被违规访问和未授权使用。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">建立完整的审计机制,对数据生命周期的全流程进行监控与审计,防止您的个人信息遭遇未经授权的访问、公开披露、使用、修改、人为或意外的损坏或丢失。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">其他可行的安全组织和管理措施:</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、在我们从第三方间接收集您的个人信息前,我们会明确以书面形式(如合作协议、承诺书)要求该第三方在已经取得您明示同意后收集以及处理(如共享等)个人信息,在书面协议层面要求第三方对个人信息来源的合法性和合规性作出承诺,如第三方有违反行为的,我们会明确要求对方承担相应法律责任;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">2、在我们向业务合作伙伴共享您的个人信息前,我们会严格要求合作伙伴的信息保护义务与责任,并要求业务合作伙伴在合作前需与</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">签署关于数据安全的保护协议,一旦业务合作伙伴有任何违反协议的行为,将须承担相应法律责任;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">3、我们建立了合理有效、科学健全的安全应急响应体系,明确了网络安全事件的分类分级标准、安全应急响应组织及职责,并根据安全事件的不同类型和级别制定了适当的应急响应预案,明确规范了安全事件的报告流程和应急响应处置流程。同时,我们还具备“</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">”安全应急响应中心,由专业的安全技术和运营团队负责维护,便于及时有效的响应、处置各类安全漏洞和突发事件,联合相关部门进行安全事件溯源和打击;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">4、如不幸发生个人信息安全事件的,我们将按照法律法规的要求,及时向您告知安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施等。我们将及时将事件相关情况以邮件、信函、电话、推送通知等方式告知您,难以逐一告知个人信息主体时,我们会采取合理、有效的方式发布公告。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">5、请您知悉并理解,互联网并非绝对安全的环境,我们强烈建议通过安全方式、使用复杂密码,协助我们保证您的账号安全。如发现自己的个人信息泄密,尤其是您自己的账户或密码发生泄露,请立即根据本政策文末中提供的联系方式联络我们,以便我们采取相应措施来保护您的个人信息安全。</span>
|
||||
</p>
|
||||
<p><strong>六、您如何管理您的个人信息</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">您对您的个人信息享有以下权利:</span></p>
|
||||
<p><strong>(一)访问权</strong></p>
|
||||
<p><strong>1、账号信息</strong><span style="color: rgb(51, 51, 51);">:您可以通过相关产品页面随时登陆您的个人账号,随时查询或访问您的账号中个人资料信息,包括:头像、昵称、星座、城市等。例如:“头像/昵称”信息在</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">APP中的访问路径为:我的—头像栏;在</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">微信小程序的访问路径为:我的->点击个人头像->点击头像右下角编辑icon可进入资料编辑页面。</span>
|
||||
</p>
|
||||
<p><strong>2、使用信息</strong><span style="color: rgb(51, 51, 51);">:您可以通过相关产品页面随时查阅您的使用信息,包括:订单记录、浏览记录、动态记录等。例如:“浏览记录”信息在</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">APP和微信小程序中的访问路径为:我的—足迹;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">3、财产信息:您可以通过</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">APP 我的-钱包,以及</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">微信公众号-钱包查阅;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">4、</span><strong>其他信息:您也可以在【我的】-【帮助与反馈】-【个人信息收集清单】中集中查询您的网络身份标识和鉴权信息、身份信息、用户基本资料、个人财产信息、用户使用过程信息、设备信息、内容制作与发布。如您在访问过程中遇到操作问题或如需获取其他前述方法无法获知的个人信息内容,您可通过本政策第九节提供的方式联系我们,我们将在核实您的身份后在合理期限内向您提供,但法律法规另有规定或本政策另有约定的除外。</strong>
|
||||
</p>
|
||||
<p><em>我们会按照如下规则进行个性化推荐或定向推送,并为您提供相应的退出机制:</em></p>
|
||||
<p><em>我们会根据您的喜欢为您提供个性化的推广内容,</em></p>
|
||||
<p><em>例如在主页推荐房间、派对 -
|
||||
推荐;您可以通过“我的-设置-个性化推荐”-关闭。关闭后,您看到的相关内容以房间活跃值默认展示。</em></p>
|
||||
<p><strong>(二)复制权</strong></p>
|
||||
<p><strong>若您需要复制我们收集的关于你本人的基本资料、身份信息的,您可通过本政策第九节提供的方式联系我们,我们将在核实您的身份后在合理期限内向您提供,或在技术可行的前提下根据您的请求将您的个人信息转移至指定的个人信息处理者,但法律法规另有规定或本政策另有约定的除外。</strong>
|
||||
</p>
|
||||
<p><strong>(三)更正/修改权</strong></p>
|
||||
<p>
|
||||
<strong>若您发现您提供给我们的个人信息存在登记错误、不完整或有更新的,您可在我们产品和/或服务中更正/修改您的相关个人信息。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、对于您的部分个人信息,您可以按照相关功能页面的指引和设置在线进行更正/修改。例如“头像/昵称”信息更正/修改路径为:我的—头像栏—编辑资料;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、对于您在行使上述权利过程中遇到的困难,或者其他可能目前无法向您提供在线自行更正/修改服务的,经过对您身份的验证,且更正/修改不影响信息的客观性和准确性的情况下,您</span><strong>有权对错误或不完整的信息作出更正或修改,或在特定情况下,尤其是数据错误时,通过我们公布的反馈与报错等措施将您的更正/修改申请提交给我们,或联系我们(联系方式:详见下文第九节),要求我们更正或修改您的数据,但法律法规另有规定的除外。但出于安全性和身份识别的考虑,您可能无法修改注册时提交的某些初始注册信息。</strong>
|
||||
</p>
|
||||
<p><strong>(四)删除权</strong></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">1、对于您提供的部分个人信息,您可以自行通过我们提供的相关产品和服务的功能页面,主动删除您提供信息。例如:“</span><strong>头像/昵称”信息在羽声语音APP中的删除路径为:【我的-个人主页-资料】。您也可以自主删除您发布的视频、动态、图片等。一旦您删除后,我们即会对此类信息进行删除或匿名化处理,法律法规另有规定的除外</strong><span
|
||||
style="color: rgb(51, 51, 51);">。</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">2、在以下情形中,</span><strong>您可以通过本政策第九节提供的联系方式</strong><span
|
||||
style="color: rgb(51, 51, 51);">向我们提出删除个人信息的请求,但已做匿名化处理或法律法规另有规定的除外:</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(1)如果我们处理个人信息的行为违反法律法规;</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(2)如果我们收集、使用您的个人信息,却未征得您的明确同意;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(3)如果我们处理个人信息的行为严重违反了该政策;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(4)如果您主动注销了账号;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(5)当我们终止服务及运营时。</span></p>
|
||||
<p><strong>(五)撤回同意权</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、我们提供的产品或服务的部分功能需要获得您使用设备的相关权限(包括:位置、相机、麦克风等,详见本隐私政策第二节第(十二)条“我们获取的设备权限”,具体以产品实际获取的功能为准)。</span><strong>您可以在授权后随时撤回(或停止)对该权限的继续授权</strong><span
|
||||
style="color: rgb(51, 51, 51);">,包括通过您设备中的设置页面或</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音</span><span
|
||||
style="color: rgb(51, 51, 51);">APP的相关路径(“我的-设置-隐私-隐私权限设置”)撤回相关授权。示例路径如下:</span>
|
||||
</p>
|
||||
<p>
|
||||
<strong>(1)位置的权限:您可通过【我的-设置-隐私-隐私权限设置-允许羽声语音直播访问位置信息】撤回同意;</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>(2)相机的权限:您可通过【我的-设置-隐私-隐私权限设置-允许羽声语音直播访问相机】撤回同意;</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>(3)麦克风的权限:您可通过【我的-设置-隐私-隐私权限设置-允许羽声语音直播访问相机】撤回同意;</strong>
|
||||
</p>
|
||||
<p><strong>(4)日历的权限:您可通过【我的-系统设置-系统权限管理】撤回同意。</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、</span><strong>就我们通过短信的方式向您发送的商业性服务信息,如果您不想收到此类信息,您可以通过联系我们(联系方式:详见下文第九节),或者通过编辑“T”或“TD”并回复短信进行退订,提请注意:我们不会就您申请退订额外收取任何费用,但可能会发生一定的通信或者网络费用,具体以通信运营商与您约定为准,退订成功后我们将不再向您发送此类型的短信。就我们通过您设备的系统通知向你推送的内容,如果您不想收到此类信息,你可选择在设备中关闭羽声语音直播的通知功能</strong><span
|
||||
style="color: rgb(51, 51, 51);">。</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">3、对于合作方使用或我们转让、公开披露您的个人信息,您可以通过我们的相关功能页面或联系我们、合作方,撤回您的授权,但法律法规另有规定或本隐私政策另有约定的除外。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">4、您可以通过卸载</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音</span><span
|
||||
style="color: rgb(51, 51, 51);">App的方式撤回我们通过当前设备对您的个人信息的收集能力。</span>
|
||||
</p>
|
||||
<p><strong>5、当您收回同意后,我们将不再处理相应的个人信息。但您收回同意的决定,不会影响此前基于您的授权而开展的个人信息处理。当您更新APP版本后,未经您的明确同意,我们不会更改您之前设置的权限状态。</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>6、对于您无法直接通过上述路径改变授权同意或撤回同意的,您均可通过本政策第九节提供的方式联系我们进行处理,但法律法规另有规定或本政策另有约定的除外。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(六)注销权</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">我们向您提供账户注销的途径。在您符合国家相关法律法规规定及约定注销条件的情况下,可以通过本隐私政策预留的联系方式(</span><strong>详见下文第九节</strong><span
|
||||
style="color: rgb(51, 51, 51);">)或在线申请注销您的账户。</span></p>
|
||||
<p><strong>提请注意:当您注销账号后,您将无法再以该账号登录和使用我们的产品与服务;且该账号在羽声语音及旗下的其他产品与服务使用期间已产生的但未消耗完毕的权益及未来的预期利益等全部权益将被清除;该账号下的内容、信息、数据、记录等将会被删除或匿名化处理(但法律法规另有规定或监管部门另有要求的除外,如依据《中华人民共和国网络安全法》规定,您的网络操作日志将至少保留六个月的时间);羽声语音账号注销完成后,将无法恢复。更多关于羽声语音账号注销的流程、条件等事项请详见《帐号注销须知》。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">如您在谨慎考虑后仍执意决定注销您的</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">账号的,您可以在您使用的我们的产品/服务的相关功能设置页面或根据操作指引向我们提交注销申请,</span><strong>羽声语音APP的在线申请注销路径为:【我的】-【设置】-【账号与安全】-【安全中心】-【注销账号】;羽声语音直播微信小程序可以选择通过上述羽声语音APP注销路径、联系客服或者通过本隐私政策第九节预留的联系方式申请注销。</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>在您主动注销账户之后,我们将停止为您提供产品或服务,根据适用法律的要求删除您的个人信息,或使其匿名化处理。</strong>
|
||||
</p>
|
||||
<p><strong>(七)约束信息系统自动决策</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">在某些业务功能中,我们可能仅依据信息系统、算法等在内的非人工自动决策机制做出决定。如果这些决定显著影响您的合法权益,您有权通过本政策第九节提供的联系方式要求我们做出解释并拒绝我们仅通过自动化决策的方式作出决定,我们也将在不侵害</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音直播</span><span
|
||||
style="color: rgb(51, 51, 51);">商业秘密或其他用户权益、社会公共利益、国家利益的前提下做出合理解释、处理。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(</span><strong>八)我们对去世用户的个人信息保护</strong>
|
||||
</p>
|
||||
<p><strong>1.
|
||||
羽声语音直播将根据《个人信息保护法》的相关规定保护死者个人信息。羽声语音用户(仅限自然人)去世后,其近亲属为了自身的合法、正当利益,可以通过本隐私政策第九节“联系我们”中公示的联系方式,对去世用户的相关个人信息行使查阅、复制、更正、删除等权利,但是去世用户生前另有安排的除外。</strong>
|
||||
</p>
|
||||
<p><strong>2.
|
||||
您理解并确认,为了充分保护去世用户的个人信息权益,申请行使本条权利的去世用户近亲属需要根据羽声语音直播的指定流程或客服提示,提交去世用户的身份证明文件、死亡证明文件、申请人的身份证明文件、申请人与去世用户的亲属关系证明文件,并提供申请行使的权利种类、目的。更多关于去世用户的个人信息保护流程、条件等事项请联系在线客服。</strong>
|
||||
</p>
|
||||
<p><strong>(九)响应您的上述请求</strong></p>
|
||||
<p>
|
||||
<strong>如果您在行使上述权利、处置您的个人信息时有任何疑问,您均可以通过本隐私政策第九节中公示的联系方式与我们沟通解决。</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>为保障安全,当您提出前述请求时,您需要提供上述要求材料,或以其他方式证明您的身份,再处理您的请求,若您拒绝提供相应证明材料,我们将无法响应您的请求。我们将在15日内做出答复</strong><span
|
||||
style="color: rgb(51, 51, 51);">。在以下情形中,按照法律法规要求,我们将无法响应您的请求:</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、与国家安全、国防安全、国家利益有关的;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、与公共安全、公共卫生、重大公共利益有关的;</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">3、与犯罪刑事侦查、起诉、立案、审判和执行判决等有关的;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">4、有充分证据表明个人信息主体存在主观恶意串通妨碍第三人行使合法权益或滥用权利使其他个人、组织的合法权益受到严重损害的;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">5、响应您的请求将导致您或其他个人、组织的合法权益受到严重损害的;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">6、涉及商业秘密的。</span></p>
|
||||
<p><strong>七、未成年人保护</strong></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">我们的产品、网站和服务主要面向成年人。</span><strong>您知悉,羽声语音直播将依赖用户提供的个人信息判断用户是否为未成年人</strong><span
|
||||
style="color: rgb(51, 51, 51);">。若您是未成年人,建议您及您的监护人仔细阅读本政策,并在征得您的监护人同意的前提下使用我们的产品或服务或向我们提供信息。对于经父母或监护人同意使用我们的产品或服务而收集未成年人个人信息的情况,我们只会在法律法规允许、父母或监护人明确同意或者保护未成年人所必要的情况下使用、共享、转让或披露此信息。</span>
|
||||
</p>
|
||||
<p><strong>特别地,若您是14周岁以下的儿童,将适用《羽声语音儿童个人信息保护规则》,建议您及您的监护人仔细阅读《羽声语音儿童个人信息保护规则》,并在征得您的监护同意的前提下使用我们的产品或服务。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">若您是未成年人的监护人,一旦发现未成年人虚报年龄注册账号的,可通过本政策第九节所述方式向我们提出中止/终止该未成年人的账号或者要求向该未成年人提供青少年保护服务模式下的产品与/或服务。为了验证请求方为未成年人的监护人,特别是当您作为监护人提出资金类申请时,我</span><strong>们可能需要您向我们提供被监护人以及监护人的身份证(正面及反面)复印件/扫描件一份、可证明法定监护关系的有效法律文件(如出生证明、户口本)以及监护人手机号码、收款账号信息(如需),以保障用户的账号与资金安全。我们在收到您的上述文件后,会及时审核其真实性和有效性,并请确保监护人的手机畅通,以便我们的专业客服联系您进一步核实身份(如需)。同时,我们将依法记录、保存验证身份信息及验证结果</strong><span
|
||||
style="color: rgb(51, 51, 51);">,这些信息仅供完成验证、争议解决服务之目的,或者其他法律法规所规定的用途,我们向您承诺,我们会以最大努力保障您的个人信息安全,未经您明示授权不会用作其他目的。以上信息包含您及您所监护的未成年人的个人敏感信息,您有权拒绝提供,但我们收集这些信息是为了调查事实与帮助您解决问题,如您拒绝提供上述信息,我们可能无法向您及时反馈投诉、申诉或咨询结果。</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">若您是未成年人的监护人,当您对您所监护的未成年人的个人信息保护有任何相关疑问时,请通过第九节“联系我们”中公示的联系方式与我们联系。</span>
|
||||
</p>
|
||||
<p><strong>八、本政策的更新</strong></p>
|
||||
<p>
|
||||
<strong>为保证您能够获得更好的服务并应平台业务调整以及未来发展,本政策也会与时俱进随之更新。但在更新的同时,我们会以单独、明显的方式获取您的授权。</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>我们在应用程序、官方网站更新版本后或官方发出公告后以合理、适当、明显的方式提醒您相关内容的更新,以便您能更快了解您权利的更迭。</strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong>对于重大变更,我们还会提供更为显著的通知方式(我们会通过包括但不限于邮件、短信、公告、首页或在浏览页面做特别提示等方式,来向您表达政策的更新内容)。</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">本政策所指的重大变更包括但不限于:</span></p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(一)我们的服务模式发生重大变化。如处理个人信息的目的、处理的个人信息类型、个人信息的使用方式等;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(二)我们在所有权结构、组织架构等方面发生重大变化。如业务调整、破产并购等引起的所有者变更等;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">(三)个人信息共享、转让或公开披露的主要对象发生变化;</span>
|
||||
</p>
|
||||
<p><span
|
||||
style="color: rgb(51, 51, 51);">(四)您参与个人信息处理方面的权利及其行使方式发生重大变化。</span>
|
||||
</p>
|
||||
<p><strong>九、联系我们</strong></p>
|
||||
<p>
|
||||
<strong>如您对本政策(或您个人信息的相关事宜)有投诉、举报、意见或建议的,可以通过如下方式与我们(陕西启星汇申网络科技有限公司)联系,我们将在15天内予以您答复:</strong>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">1、</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">羽声语音</span><span
|
||||
style="color: rgb(51, 51, 51);">站内客服:【我的】-【在线客服】-输入“人工客服”进行咨询;</span>
|
||||
</p>
|
||||
<p><span style="color: rgb(51, 51, 51);">2、人工客服电话:</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">17531991222</span></p>
|
||||
<p><span style="color: rgb(51, 51, 51);">3、个人信息保护负责人电话:</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">17531991222</span></p>
|
||||
<p style="text-align: left;"><span
|
||||
style="color: rgb(51, 51, 51);">4、我们还设立了个人信息保护专职部门,您可以写信至:</span><span
|
||||
style="font-family: 宋体;">陕西省咸阳市高新技术产业开发区高科三路科技企业孵化园3栋4层</span><span
|
||||
style="color: rgb(51, 51, 51);">法务合规部(收);邮编</span><span
|
||||
style="color: rgb(51, 51, 51); font-family: 宋体;">710000</span></p>
|
||||
<p><strong>十、其他</strong></p>
|
||||
<p><strong>本政策的解释、执行及争议解决均适用中华人民共和国法律(不包括冲突法)。因本政策产生争议的,双方应首先友好协商,协商不成的,您同意通过被告所在地有管辖权的法院提起诉讼来寻求解决方案。</strong>
|
||||
</p>
|
||||
<p><strong>陕西启星汇申网络科技有限公司 </strong></p>
|
||||
<p><strong>陕西省咸阳市高新技术产业开发区高科三路科技企业孵化园3栋4层</strong></p>
|
||||
<p><span
|
||||
style="color: rgb(26, 26, 26); background-color: rgb(255, 255, 255);">陕ICP备2024054760号-7A</span>
|
||||
</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p style="text-align: left;"><span style="font-family: 宋体;"> </span></p></body>
|
||||
</html>
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.xscm.moduleutil;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
public class BaseEvent {
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
package com.xscm.moduleutil.activity;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.databinding.ViewDataBinding;
|
||||
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.blankj.utilcode.util.ActivityUtils;
|
||||
import com.blankj.utilcode.util.BarUtils;
|
||||
import com.blankj.utilcode.util.LogUtils;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import com.xscm.moduleutil.R;
|
||||
import com.xscm.moduleutil.dialog.LoadingDialog;
|
||||
import com.xscm.moduleutil.utils.BackgroundManager;
|
||||
import com.xscm.moduleutil.utils.ColorManager;
|
||||
import com.xscm.moduleutil.utils.DisplayUtil;
|
||||
import com.xscm.moduleutil.widget.QXGiftDriftView;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends AppCompatActivity
|
||||
implements BackgroundManager.BackgroundUpdateListener, ColorManager.ColorChangeListener {
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
// 设置字体缩放比例为1.0f,即不跟随系统字体大小变化
|
||||
super.attachBaseContext(DisplayUtil.attachBaseContext(newBase, 1.0f));
|
||||
}
|
||||
|
||||
protected VDB mBinding;
|
||||
|
||||
@Subscribe (threadMode = ThreadMode.MAIN)
|
||||
public void onEvent(Object event) {
|
||||
}
|
||||
|
||||
private LoadingDialog mLoadingDialog;
|
||||
// 添加广播接收器成员变量
|
||||
private BroadcastReceiver mLogoutReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if ("com.xscm.moduleutil.ACTION_USER_LOGOUT".equals(intent.getAction())) {
|
||||
// 在这里处理用户登出后的UI更新
|
||||
// 例如:隐藏需要登录才能显示的控件
|
||||
// 或者跳转到登录状态的页面
|
||||
handleUserLogout();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 处理用户登出的方法
|
||||
protected void handleUserLogout() {
|
||||
// 子类可以重写此方法处理具体的登出逻辑
|
||||
// 例如:更新UI状态、清除本地数据等
|
||||
|
||||
ActivityUtils.finishAllActivities();
|
||||
}
|
||||
|
||||
QXGiftDriftView qxGiftDriftView;
|
||||
protected void doDone(){}
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().getDecorView().setBackgroundResource(R.mipmap.log_bj);
|
||||
setContentView(getLayoutId());
|
||||
doDone();
|
||||
// 隐藏标题栏
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().hide();
|
||||
}
|
||||
mBinding = DataBindingUtil.setContentView(this, getLayoutId());
|
||||
mBinding.setLifecycleOwner(this);
|
||||
ARouter.getInstance().inject(this);
|
||||
BarUtils.setStatusBarLightMode(this, isLightMode());
|
||||
BarUtils.transparentStatusBar(this);
|
||||
initView();
|
||||
initData();
|
||||
initCompleted();
|
||||
|
||||
// 注册背景更新监听器
|
||||
BackgroundManager.getInstance().addListener(this);
|
||||
// 尝试加载网络背景
|
||||
loadNetworkBackground();
|
||||
// 注册颜色变化监听器
|
||||
ColorManager.getInstance().addColorChangeListener(this);
|
||||
|
||||
// 注册登出广播接收器
|
||||
IntentFilter filter = new IntentFilter("com.xscm.moduleutil.ACTION_USER_LOGOUT");
|
||||
registerReceiver(mLogoutReceiver, filter);
|
||||
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
// 在Activity中
|
||||
private static final int REQUEST_OVERLAY_PERMISSION = 1001;
|
||||
|
||||
private void checkAndRequestOverlayPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (!Settings.canDrawOverlays(this)) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("需要悬浮窗权限")
|
||||
.setMessage("应用需要悬浮窗权限才能显示飘屏效果")
|
||||
.setPositiveButton("去设置", (dialog, which) -> {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||
Uri.parse("package:" + getPackageName()));
|
||||
startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION);
|
||||
})
|
||||
.setNegativeButton("取消", null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == REQUEST_OVERLAY_PERMISSION) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (Settings.canDrawOverlays(this)) {
|
||||
ToastUtils.show("已获得悬浮窗权限");
|
||||
} else {
|
||||
ToastUtils.show("未获得悬浮窗权限");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onColorChanged() {
|
||||
// 在主线程中更新UI
|
||||
runOnUiThread(this::updateUIColors);
|
||||
}
|
||||
|
||||
// 子类可以重写此方法来更新UI颜色
|
||||
protected void updateUIColors() {
|
||||
// 默认实现,子类可以覆盖
|
||||
}
|
||||
|
||||
//在类中添加以下成员变量
|
||||
private Handler timerHandler = new Handler();
|
||||
private Runnable timerRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// 调用你要执行的方法
|
||||
// executePeriodicTask();
|
||||
|
||||
// 每10秒执行一次
|
||||
timerHandler.postDelayed(this, 10000);
|
||||
}
|
||||
};
|
||||
|
||||
// 启动定时器的方法
|
||||
private void startTimer() {
|
||||
timerHandler.postDelayed(timerRunnable, 10000);
|
||||
}
|
||||
|
||||
protected void loadNetworkBackground() {
|
||||
// 只有当已经有背景URL时才加载
|
||||
String backgroundUrl = BackgroundManager.getInstance().getBackgroundUrl();
|
||||
if (backgroundUrl != null && !backgroundUrl.isEmpty()) {
|
||||
// 检查是否有已加载的drawable
|
||||
Drawable cachedDrawable = BackgroundManager.getInstance().getBackgroundDrawable();
|
||||
if (cachedDrawable != null) {
|
||||
getWindow().getDecorView().setBackground(cachedDrawable);
|
||||
} else {
|
||||
// 加载网络背景
|
||||
BackgroundManager.getInstance().loadBackgroundDrawable(this, new BackgroundManager.BackgroundLoadCallback() {
|
||||
@Override
|
||||
public void onLoadSuccess(Drawable drawable) {
|
||||
getWindow().getDecorView().setBackground(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed() {
|
||||
// 加载失败时使用默认背景
|
||||
getWindow().getDecorView().setBackgroundResource(R.mipmap.activity_bj);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackgroundUpdated(Drawable drawable) {
|
||||
// 当背景更新时,更新当前Activity的背景
|
||||
if (drawable != null) {
|
||||
getWindow().getDecorView().setBackground(drawable);
|
||||
}
|
||||
}
|
||||
|
||||
// 提供一个方法供子类调用,用于设置背景URL
|
||||
protected void setNetworkBackgroundUrl(String url) {
|
||||
BackgroundManager.getInstance().setBackgroundUrl(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resources getResources() {//禁止app字体大小跟随系统字体大小调节
|
||||
Resources resources = super.getResources();
|
||||
if (resources != null && resources.getConfiguration().fontScale != 1.0f) {
|
||||
android.content.res.Configuration configuration = resources.getConfiguration();
|
||||
configuration.fontScale = 1.0f;
|
||||
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
static float fontScale = 1f;
|
||||
|
||||
// @Override
|
||||
// public Resources getResources() {
|
||||
// Resources resources = super.getResources();
|
||||
// return DisplayUtil.getResources(this,resources,fontScale);
|
||||
// }
|
||||
|
||||
public void setFontScale(float fontScale) {
|
||||
this.fontScale = fontScale;
|
||||
DisplayUtil.recreate(this);
|
||||
}
|
||||
|
||||
public boolean isLightMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void initData();
|
||||
|
||||
protected abstract void initView();
|
||||
|
||||
protected void initCompleted() {
|
||||
}
|
||||
|
||||
protected abstract int getLayoutId();
|
||||
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
EventBus.getDefault().unregister(this);
|
||||
super.finish();
|
||||
LogUtils.e(this.getComponentName()+"========finish");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
// 移除背景更新监听器
|
||||
BackgroundManager.getInstance().removeListener(this);
|
||||
// 移除颜色变化监听器
|
||||
ColorManager.getInstance().removeColorChangeListener(this);
|
||||
if (mBinding != null) {
|
||||
mBinding.unbind();
|
||||
}
|
||||
try {
|
||||
unregisterReceiver(mLogoutReceiver);
|
||||
} catch (Exception e) {
|
||||
// 忽略异常
|
||||
}
|
||||
|
||||
try {
|
||||
unregisterReceiver(mLogoutReceiver);
|
||||
} catch (Exception e) {
|
||||
// 忽略异常
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public void showLoading(String content) {
|
||||
if (mLoadingDialog == null) {
|
||||
mLoadingDialog = new LoadingDialog(this,content);
|
||||
}
|
||||
if (!mLoadingDialog.isShowing()) {
|
||||
mLoadingDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
public void showLoading() {
|
||||
if (mLoadingDialog == null) {
|
||||
mLoadingDialog = new LoadingDialog(this);
|
||||
}
|
||||
if (!mLoadingDialog.isShowing()) {
|
||||
mLoadingDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
public void disLoading() {
|
||||
if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
|
||||
mLoadingDialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
View view = getCurrentFocus();
|
||||
if (isShouldHideInput(view, ev)) {
|
||||
InputMethodManager Object = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (Object != null) {
|
||||
Object.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return super.dispatchTouchEvent(ev);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//判断是否隐藏键盘
|
||||
public boolean isShouldHideInput(View v, MotionEvent event) {
|
||||
if (v != null && (v instanceof EditText)) {
|
||||
int[] leftTop = {0, 0};
|
||||
//获取输入框当前的location位置
|
||||
v.getLocationInWindow(leftTop);
|
||||
int left = leftTop[0];
|
||||
int top = leftTop[1];
|
||||
int bottom = top + v.getHeight();
|
||||
int right = left + v.getWidth();
|
||||
if (event.getX() > left && event.getX() < right
|
||||
&& event.getY() > top && event.getY() < bottom) {
|
||||
// 点击的是输入框区域,保留点击EditText的事件
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
LogUtils.e(this.getComponentName()+"========onResume");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
LogUtils.e(this.getComponentName()+"=========onPause");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
LogUtils.e(this.getComponentName()+"=========onStop");
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.xscm.moduleutil.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.ViewDataBinding;
|
||||
|
||||
|
||||
import com.xscm.moduleutil.bean.room.RoomInfoResp;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class BaseRoomFragment<P extends BaseRoomPresenter, VDB extends ViewDataBinding> extends BaseMvpFragment<P, VDB> implements BaseRoomContacts.View {
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
unRegisterWheatViews();
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView() {
|
||||
registerWheatViews();
|
||||
}
|
||||
|
||||
/**
|
||||
* 房间信息
|
||||
*/
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void roomInfo(RoomInfoResp resp) {
|
||||
roomInfoUpdate(resp);
|
||||
}
|
||||
|
||||
public abstract void roomInfoUpdate(RoomInfoResp resp);
|
||||
public abstract void registerWheatViews();
|
||||
public abstract void unRegisterWheatViews();
|
||||
|
||||
public abstract int[] collectCurrentCardiacValues();
|
||||
protected void tzblChanged() {
|
||||
|
||||
}
|
||||
|
||||
private int getAmativenessWheatMaoziLevel(int value) {
|
||||
if (value >= 52000) {
|
||||
return 3;
|
||||
} else if (value >= 10000) {
|
||||
return 2;
|
||||
} else if (value >= 1000) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.xscm.moduleutil.base
|
||||
|
||||
import com.xscm.moduleutil.utils.config.EnvironmentEnum
|
||||
|
||||
|
||||
object ExternalResConstants {
|
||||
//================================================================================MQTT======================================================================================
|
||||
// var IS_MQTT_RELEASE = true
|
||||
// val MQTT_PATH_DEBUG = "tcp://1.13.181.248"
|
||||
// val MQTT_PATH_RELEASE = "tcp://1.13.101.98"
|
||||
//
|
||||
// fun MQTT_PATH(): String {
|
||||
// return if (IS_MQTT_RELEASE) {
|
||||
// MQTT_PATH_RELEASE
|
||||
// } else {
|
||||
// MQTT_PATH_DEBUG
|
||||
// }
|
||||
// }
|
||||
//================================================================================HTTP======================================================================================
|
||||
var IS_HTTP_RELEASE = true
|
||||
val HTTP_PATH_DEBUG:EnvironmentEnum = EnvironmentEnum.TEST
|
||||
val HTTP_PATH_RELEASE:EnvironmentEnum = EnvironmentEnum.PRODUCTION
|
||||
fun HTTP_PATH(): EnvironmentEnum {
|
||||
return if (IS_HTTP_RELEASE) {
|
||||
HTTP_PATH_RELEASE
|
||||
} else {
|
||||
HTTP_PATH_DEBUG
|
||||
}
|
||||
}
|
||||
//================================================================================END======================================================================================
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.xscm.moduleutil.base
|
||||
|
||||
/**
|
||||
* Created by xscm on 2020/7/23.
|
||||
* 描述:web url 常量
|
||||
*/
|
||||
object WebUrlConstants {
|
||||
val BASE_URL = CommonAppContext.getInstance().currentEnvironment.h5Url
|
||||
|
||||
/**青少年模式*/
|
||||
val WEB_ADOLESCENT_URL = BASE_URL + "/web/index.html#/pages/feedback/teenage?id=%s"
|
||||
|
||||
val WEB_SET_GROUP_URL = BASE_URL + "/web/index.html#/pages/union/setGroup?id=%s&guildId=%s"
|
||||
|
||||
/**举报*/
|
||||
val WEB_REPORT_URL =
|
||||
BASE_URL + "/web/index.html#/pages/feedback/report?id=%s&fromType=%d&fromId=%s"
|
||||
|
||||
/**规则*/
|
||||
val WEB_RULES_URL = BASE_URL + "/web/index.html#/pages/other/taskDesc"
|
||||
|
||||
/**道具商城*/
|
||||
val WEB_PROP_MALL_URL = BASE_URL + "/web/index.html#/pages/prop/propMall?id=%s"
|
||||
|
||||
/**公会*/
|
||||
val WEB_GUILD_URL = BASE_URL + "/web/index.html#/pages/union/index?id=%s"
|
||||
|
||||
/**等级*/
|
||||
val WEB_GRADE_URL = BASE_URL + "/web/index.html#/pages/other/grade?id=%s"
|
||||
|
||||
/**反馈*/
|
||||
val WEB_HELP_URL = BASE_URL + "/web/index.html#/pages/feedback/help?id=%s"
|
||||
|
||||
/**邀请*/
|
||||
val WEB_INVITATION_URL = BASE_URL + "/web/index.html#/pages/other/income?id=%s"
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.xscm.moduleutil.bean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author qx
|
||||
* @data 2025/6/3
|
||||
* @description: 这是广场中的列表数据
|
||||
*/
|
||||
@Data
|
||||
public class CircleListBean {
|
||||
public int id;//语圈ID
|
||||
public int user_id;//用户ID
|
||||
public String nickname;//用户昵称
|
||||
public String avatar;//用户头像
|
||||
public int is_like;//我是否点赞(0没有,1点赞)
|
||||
public int sex;//性别 1男2女
|
||||
public String content;//内容
|
||||
public String like_num;//点赞数
|
||||
public String rewards_num; //打赏金额
|
||||
public String is_room;//作者是否在房间中(1在,0不在)
|
||||
public String room_id;//作者所在房间ID (is_room =0 此值小于0 )
|
||||
public String comment_num;//评论数
|
||||
public int is_recommend;//1非推荐2推荐
|
||||
public String ip;//活跃地址
|
||||
public String images;////图片 JSON字符串 封面获取第一张
|
||||
public String createtime;//时间
|
||||
public String topic_id;
|
||||
public String share_url;
|
||||
public List<HeatedBean> title;//话题列表
|
||||
|
||||
public String nobility_image;//贵族图标
|
||||
public String nickname_color = "";//昵称颜色
|
||||
public String mic_cycle;//麦圈
|
||||
|
||||
public String read_num;//阅读数
|
||||
public List<LikeList> like_list;
|
||||
|
||||
|
||||
@Data
|
||||
public class LikeList {
|
||||
public String user_id;
|
||||
public String nickname;
|
||||
public String avatar;
|
||||
public int age;//年龄
|
||||
public String sex;
|
||||
public String constellation;//星座
|
||||
public String birthday;//生日
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
/**
|
||||
* 项目名称:羽声语音
|
||||
* 时间:2025/11/27 16:47
|
||||
* 用途:
|
||||
*/
|
||||
class FamilyEarnings {
|
||||
|
||||
var id: Int=0
|
||||
var nickname: String=""
|
||||
var avatar: String=""
|
||||
var user_code: String=""
|
||||
var earnings: String=""
|
||||
var createtime: Long=0
|
||||
var gift_name: String=""
|
||||
var gift_price: String=""
|
||||
|
||||
/* id 列表 id
|
||||
|
||||
nickname 用户昵称
|
||||
|
||||
avatar
|
||||
|
||||
user_code
|
||||
|
||||
earnings 收益
|
||||
createtime
|
||||
|
||||
gift_name 礼物名称
|
||||
|
||||
gift_price 礼物价格*/
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
class HeartCpBean : Serializable {
|
||||
|
||||
|
||||
/* {
|
||||
"code": 1,
|
||||
"msg": "\u6210\u529f",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"user_id1": 20001,
|
||||
"user_id2": 20003,
|
||||
"status": 1,
|
||||
"level": 1,
|
||||
"exp": 9198,
|
||||
"createtime": 1763720783,
|
||||
"user_info1": {
|
||||
"user_id": 20001,
|
||||
"nickname": "\u9ad8\u5174\u7684\u5c0f\u6d77\u817e",
|
||||
"avatar": "https:\/\/yusheng-1369267578.cos.ap-guangzhou.myqcloud.com\/images\/ios_images\/1761615690733.jpeg"
|
||||
},
|
||||
"user_info2": {
|
||||
"user_id": 20003,
|
||||
"nickname": "\u79c0\u4e3d\u7684\u978b\u57ab",
|
||||
"avatar": "https:\/\/yusheng-1369267578.cos.ap-guangzhou.myqcloud.com\/images\/android_images\/33e31b18577856c4f10906b7cabaa698.jpg"
|
||||
},
|
||||
"next_level_exp": 802,
|
||||
"pendant": "https:\/\/cos.xscmmidi.site\/admin\/520liuxingyu_17637096968287.mp4",
|
||||
"gift_log": [
|
||||
{
|
||||
"id": 323,
|
||||
"room_id": 6003,
|
||||
"from_user_id": 20001,
|
||||
"to_user_id": 20003,
|
||||
"gift_id": 313,
|
||||
"num": 1,
|
||||
"cp_zone_id": 1,
|
||||
"exp": "1314",
|
||||
"exp_total": "9198",
|
||||
"remark": "\u9001\u7ed9\u79c0\u4e3d\u7684\u978b\u57ab1\u4e2a\u9e4a\u7f18\u7ec7\u68a6,\u83b7\u5f971314\u7ecf\u9a8c\u503c\uff0c\u603b\u7ecf\u9a8c\u503c\u589e\u52a0\u81f39198",
|
||||
"createtime": 1763796118,
|
||||
"gift_name": "\u9e4a\u7f18\u7ec7\u68a6",
|
||||
"from_user_info": {
|
||||
"user_id": 20001,
|
||||
"nickname": "\u9ad8\u5174\u7684\u5c0f\u6d77\u817e",
|
||||
"avatar": "https:\/\/yusheng-1369267578.cos.ap-guangzhou.myqcloud.com\/images\/ios_images\/1761615690733.jpeg"
|
||||
},
|
||||
"to_user_info": {
|
||||
"user_id": 20003,
|
||||
"nickname": "\u79c0\u4e3d\u7684\u978b\u57ab",
|
||||
"avatar": "https:\/\/yusheng-1369267578.cos.ap-guangzhou.myqcloud.com\/images\/android_images\/33e31b18577856c4f10906b7cabaa698.jpg"
|
||||
}
|
||||
}]
|
||||
},
|
||||
"api_version": ""
|
||||
}*/
|
||||
|
||||
var id: Int = 0
|
||||
var user_id1: Int = 0
|
||||
var user_id2: Int = 0
|
||||
var status: Int = 0
|
||||
var level: Int = 0
|
||||
var exp: Long = 0
|
||||
var createtime: Long = 0
|
||||
var user_info1: UserInfo = UserInfo()
|
||||
var user_info2: UserInfo = UserInfo()
|
||||
var next_level_exp: Long = 0
|
||||
var pendant: String = ""
|
||||
var gift_log: List<GiftLog> = ArrayList()
|
||||
var api_version: String = ""
|
||||
|
||||
class GiftLog : Serializable {
|
||||
var id: Int = 0
|
||||
var room_id: Int = 0
|
||||
var from_user_id: Int = 0
|
||||
var to_user_id: Int = 0
|
||||
var gift_id: Int = 0
|
||||
var num: Int = 0
|
||||
var cp_zone_id: Int = 0
|
||||
var exp: String = ""
|
||||
var exp_total: String = ""
|
||||
var remark: String = ""
|
||||
var createtime: Long = 0
|
||||
var gift_name: String = ""
|
||||
var from_user_info: UserInfo = UserInfo()
|
||||
var to_user_info: UserInfo = UserInfo()
|
||||
|
||||
class UserInfo : Serializable {
|
||||
var user_id: Int = 0
|
||||
var nickname: String = ""
|
||||
var avatar: String = ""
|
||||
}
|
||||
}
|
||||
|
||||
class UserInfo : Serializable {
|
||||
var user_id: Int = 0
|
||||
var nickname: String = ""
|
||||
var avatar: String = ""
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.xscm.moduleutil.bean;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MqttXlhEnd extends BaseEvent implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String message;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
/**
|
||||
* 项目名称:羽声语音
|
||||
* 时间:2025/11/26 18:45
|
||||
* 用途:
|
||||
*/
|
||||
class MyFamilyBean {
|
||||
var group_id: String = "" //群组id
|
||||
var name: String = "" //家族名称
|
||||
var user_id: Int = 0 //族长id
|
||||
var group_members_num: Int = 0 //签约次数 群组人数
|
||||
var group_earnings: String = "" //总计收益
|
||||
|
||||
var group_owner_info: GroupOwnerInfoBean? = null //族长信息
|
||||
|
||||
class GroupOwnerInfoBean {
|
||||
|
||||
var nickname: String = "" //昵称
|
||||
var avatar: String = "" //头像
|
||||
var dress: String = "" //头像框
|
||||
var user_code: String = "" //用户id
|
||||
var icon: List<String> = arrayListOf()
|
||||
var mic_cycle: String = "" //麦圈
|
||||
var nobility_image: String = "" //贵族
|
||||
var nickname_color: String = "" //贵族颜色
|
||||
}
|
||||
|
||||
var group_members_lists: List<GroupMembersListsBean> = arrayListOf() //
|
||||
|
||||
class GroupMembersListsBean{
|
||||
var market_value: String = "" //身价
|
||||
var nickname: String = ""
|
||||
var avatar: String = ""
|
||||
var user_code: String = ""
|
||||
var user_id: Int = 0
|
||||
var end_time: Long = 0 //签约到期时间点
|
||||
var dress: String = ""
|
||||
var icon: List<String> = arrayListOf()
|
||||
var mic_cycle: String = "" //麦圈
|
||||
var nobility_image: String = "" //贵族
|
||||
var nickname_color: String = "" //贵族颜色
|
||||
var free_renewal: Int = 0 //免费续签次数
|
||||
var today_earnings: Double = 0.0 //今日收礼收益
|
||||
var yesterday_earnings: Double = 0.0 //昨日收礼收益
|
||||
var is_online: Int = 0 //是否在线 1在线 0离线
|
||||
var is_show_sign: Int = 0 //是否显示续约按钮 1:显示 0:不显示
|
||||
|
||||
var sign_times: Int = 0 //非首签签约时长
|
||||
var sign_user_ratio : Int = 0 //非首签签约比例
|
||||
var end_day: String = "" //签约剩余时长
|
||||
|
||||
val free_re_sign_day : Int=0 //免费续签时长
|
||||
|
||||
}
|
||||
|
||||
/* "group_id": "string",
|
||||
"name": "string",
|
||||
"user_id": "string",
|
||||
"group_members_num": "string",
|
||||
"group_earnings": "string",
|
||||
"group_owner_info": {
|
||||
"nickname": "string",
|
||||
"avatar": "string",
|
||||
"dress": "string",
|
||||
"user_code": "string",
|
||||
"icon": [
|
||||
"string"
|
||||
],
|
||||
"mic_cycle": "string",
|
||||
"nobility_image": "string",
|
||||
"nickname_color": "string"
|
||||
},
|
||||
"group_members_lists": [
|
||||
{
|
||||
"market_value": "string",
|
||||
"nickname": "string",
|
||||
"avatar": "string",
|
||||
"user_code": "string",
|
||||
"user_id": "string",
|
||||
"end_time": "string",
|
||||
"dress": "string",
|
||||
"icon": [
|
||||
"string"
|
||||
],
|
||||
"mic_cycle": "string",
|
||||
"nobility_image": "string",
|
||||
"nickname_color": "string",
|
||||
"free_renewal": "string",
|
||||
"today_earnings": "string",
|
||||
"yesterday_earnings": "string"
|
||||
}
|
||||
]
|
||||
}*/
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
/**
|
||||
*com.xscm.moduleutil.bean
|
||||
*qx
|
||||
*2025/11/8
|
||||
*
|
||||
*/
|
||||
class NobilitDeatils {
|
||||
|
||||
var nobility_power_list = ArrayList<nobilityPowerItem>()
|
||||
var user_info: UserInfo? = null
|
||||
var nobility_info: NobilityInfo? = null
|
||||
|
||||
class UserInfo {
|
||||
/*"user_info": { // 用户信息
|
||||
"id": 20034, //用户Id
|
||||
"nickname": "奋斗的石头", //用户昵称
|
||||
"avatar": "http://test.vespa.qxyushen.top/data/avatar/head_pic.png" //用户头像
|
||||
}*/
|
||||
var id: Int = 0
|
||||
var nickname: String = ""
|
||||
var avatar: String = ""
|
||||
}
|
||||
|
||||
class NobilityInfo {
|
||||
/*"nobility_info": { // 爵位信息
|
||||
"status": 0, //状态: 0去开通 1去续费
|
||||
"lid": 0, //爵位ID
|
||||
"name": "", // 爵位名称
|
||||
"image": "", //爵位图片
|
||||
"end_time": 0 //结束时间
|
||||
}*/
|
||||
var status: Int = 0
|
||||
var name: String = ""
|
||||
var lid: Int = 0
|
||||
var image: String = ""
|
||||
var end_time: String = ""
|
||||
}
|
||||
|
||||
class nobilityPowerItem {
|
||||
/*"lid": 0, //爵位ID
|
||||
"name": "特权", //爵位名称
|
||||
"power_ids": "", //权限ID
|
||||
"nick_name_color": "无", //昵称颜色
|
||||
"nick_name_color_name": "无", //昵称颜色名称
|
||||
"nobility_list": [
|
||||
{
|
||||
"id": 1, //权限ID
|
||||
"name": "专属徽章", //权限名称
|
||||
"image": "", //权限图片
|
||||
"status": 0 //权限状态 : 0 不显示 1显示
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "昵称颜色",
|
||||
"image": "",
|
||||
"status": 0
|
||||
}
|
||||
|
||||
]*/
|
||||
|
||||
var lid: Int = 0
|
||||
var name: String = ""
|
||||
var power_ids: String = ""
|
||||
var nick_name_color: String = ""
|
||||
var nick_name_color_name: String = ""
|
||||
var nobility_list = ArrayList<nobilityPowerItem>()
|
||||
|
||||
class nobilityPowerItem {
|
||||
/*"id": 1, //权限ID
|
||||
"name": "专属徽章", //权限名称
|
||||
"image": "", //权限图片
|
||||
"status": 0 //权限状态 : 0 不显示 1显示*/
|
||||
var id: Int = 0
|
||||
var name: String = ""
|
||||
var image: String = ""
|
||||
var status: Int = 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
/**
|
||||
*com.xscm.moduleutil.bean
|
||||
*qx
|
||||
*2025/11/10
|
||||
*
|
||||
*/
|
||||
class NobilitList {
|
||||
|
||||
var name: String = ""
|
||||
var image: String = ""
|
||||
var pay_price: String = ""
|
||||
var power: Power? = Power()
|
||||
var lid: Int = 0
|
||||
var day : Int = 0
|
||||
class Power {
|
||||
var power_count: Int = 0
|
||||
var this_power_count: Int = 0
|
||||
var count_str: String = ""
|
||||
var list = ArrayList<PowerItem>()
|
||||
|
||||
class PowerItem {
|
||||
var id: Int = 0
|
||||
var name: String = ""
|
||||
var content: String = ""
|
||||
var image: String = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* {
|
||||
"name": "骑士",
|
||||
"image": "https://cos.xscmmidi.site/admin/ScreenShot_2025-11-05_175044_144_17623369241246.png",
|
||||
"pay_price": "388.00",
|
||||
"power": {
|
||||
"power_count": 12,
|
||||
"this_power_count": 1,
|
||||
"count_str": "12/1",
|
||||
"list": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "专属徽章",
|
||||
"content": "专属动态爵位徽章",
|
||||
"image": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
*/
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
/**
|
||||
*com.xscm.moduleutil.bean
|
||||
*qx
|
||||
*2025/11/10
|
||||
*
|
||||
*/
|
||||
class NobilityPrice {
|
||||
var lid : Int = 0
|
||||
var nobility_name : String = ""
|
||||
var nobility_image : String = ""
|
||||
var price : String = ""
|
||||
var pay_price : String = ""
|
||||
var day : Int = 0
|
||||
var end_time : String = ""
|
||||
var power_list = ArrayList<PowerItem>()
|
||||
|
||||
class PowerItem {
|
||||
var id : Int = 0
|
||||
var content : String = ""
|
||||
}
|
||||
|
||||
/* "lid": 2,
|
||||
"nobility_name": "男爵",
|
||||
"nobility_image": "https://cos.xscmmidi.site/admin/ScreenShot_2025-11-05_175121_076_17623369074684.png",
|
||||
"price": "588.00", //实付价格
|
||||
"pay_price": "588.00", //画线价格
|
||||
"day": 30,
|
||||
"power_list": [
|
||||
{
|
||||
"id": 1,
|
||||
"content": "专属动态爵位徽章"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"content": "设置昵称颜色字体"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"content": "特殊入场动画音效"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"content": "入场专属座驾动画"
|
||||
}
|
||||
],
|
||||
"end_time": "2025-12-10 10:19:20"*/
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
import com.chad.library.adapter.base.entity.MultiItemEntity
|
||||
import lombok.Data
|
||||
import java.util.ArrayList
|
||||
|
||||
/**
|
||||
* 项目名称:羽声语音
|
||||
* 时间:2025/11/20 15:13
|
||||
* 用途:心动空间中的关系实体
|
||||
*/
|
||||
@Data
|
||||
class RelationBean : MultiItemEntity {
|
||||
|
||||
var cp: UserInfo.CpInfo = UserInfo.CpInfo()
|
||||
var no_cp: List<NoCpBean> = ArrayList()
|
||||
override fun getItemType(): Int {
|
||||
|
||||
// 情况3:no_cp集合,relation_name不等于"",并且relation_list的大小是1
|
||||
if (no_cp.isNotEmpty() && no_cp[0].relation_name.isNotEmpty() && no_cp[0].relation_list.size == 1) {
|
||||
return 3
|
||||
}
|
||||
|
||||
// 情况4:no_cp集合,relation_list的大小是1
|
||||
if (no_cp.isNotEmpty() && no_cp[0].relation_list.size == 1) {
|
||||
return 4
|
||||
}
|
||||
|
||||
if (no_cp.isNotEmpty() && no_cp[0].relation_name.isNotEmpty() && no_cp[0].relation_list.size > 1){
|
||||
return 5
|
||||
}
|
||||
|
||||
// 其他情况返回5
|
||||
return 6
|
||||
}
|
||||
|
||||
class NoCpBean : MultiItemEntity{
|
||||
var relation_name: String = ""
|
||||
var relation_list: List<RelationshipBean> = ArrayList()
|
||||
override fun getItemType(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*"cp": [
|
||||
{
|
||||
"relation_name": "string",
|
||||
"relation_list": [
|
||||
{
|
||||
"nickname1": "string",
|
||||
"avatar1": "string",
|
||||
"user_id1": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"no_cp": [
|
||||
{
|
||||
"relation_name": "string",
|
||||
"relation_list": [
|
||||
{
|
||||
"user_info1": {},
|
||||
"user_info2": "string",
|
||||
"level": "string",
|
||||
"exp": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}*/
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.xscm.moduleutil.bean;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 送礼后的成功回调
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class RoomGiftData extends BaseEvent {
|
||||
private int gift_total;
|
||||
|
||||
private List<GiftUserData> gift_user_data;
|
||||
|
||||
private CpType cp_type;
|
||||
|
||||
@Data
|
||||
public static class GiftUserData {
|
||||
private String user_id;//受理人id
|
||||
private String gift_price;//礼物价格
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class CpType {
|
||||
private int cp_type;//0:不处理 1:表明心意 2:组成cp
|
||||
private String text;//发送方弹起的信息
|
||||
private String text1;//接收方弹起的信息
|
||||
private int gift_id;//礼物id
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
class SignInfo : Serializable {
|
||||
/* sign_id
|
||||
// 0 未开始 1进行中
|
||||
sign_status;
|
||||
// 签约天数
|
||||
sign_day;
|
||||
// 当前身价
|
||||
current_body_value;
|
||||
// 倒计时 时间戳
|
||||
end_time;*/
|
||||
|
||||
var sign_id: String = ""
|
||||
var sign_status: Int = 0
|
||||
var sign_day: Int = 0
|
||||
var current_body_value: Int = 0
|
||||
var end_time: Long = 0
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.xscm.moduleutil.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SingerInfo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private SongInfo song_info;
|
||||
private SongInfo next_song_info;
|
||||
|
||||
@Data
|
||||
public static class SongInfo implements Serializable{
|
||||
private static final long serialVersionUID = 1L;
|
||||
/*"id": 29,
|
||||
"room_id": 6001,
|
||||
"user_id": 20001,
|
||||
"singer_song_id": 9,
|
||||
"status": 1,
|
||||
"sort": 0,
|
||||
"createtime": 1763435086,
|
||||
"boss_user_id": 20001,
|
||||
"boss_nickname": "高兴的小海腾",
|
||||
"boss_avatar": "https://yusheng-1369267578.cos.ap-guangzhou.myqcloud.com/images/ios_images/1761615690733.jpeg",
|
||||
"boss_dress": "",
|
||||
"boss_mic_cycle": "https://cos.xscmmidi.site/admin/ripple3695_17627709565119.svga",
|
||||
"singer_user_id": 20000,
|
||||
"singer_nickname": "坚定的故事",
|
||||
"singer_avatar": "https://yusheng-1369267578.cos.ap-guangzhou.myqcloud.com/images/android_images/4ead5077435f1da7b8aae1a878bb5ac9.jpg",
|
||||
"singer_dress": "",
|
||||
"singer_mic_cycle": "https://cos.xscmmidi.site/admin/ripple3695_17627709565119.svga",
|
||||
"song_name": "公敌"*/
|
||||
private int id = 0;
|
||||
private int room_id = 0;
|
||||
private int user_id = 0;
|
||||
private int singer_song_id = 0;
|
||||
private int status = 0;
|
||||
private int sort = 0;
|
||||
private long createtime = 0;
|
||||
private int boss_user_id = 0;
|
||||
private String boss_nickname = "";
|
||||
private String boss_avatar = "";
|
||||
private String boss_dress = "";
|
||||
private String boss_mic_cycle = "";
|
||||
private int singer_user_id = 0;
|
||||
private String singer_nickname = "";
|
||||
private String singer_avatar = "";
|
||||
private String singer_dress = "";
|
||||
private String singer_mic_cycle = "";
|
||||
private String song_name = "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
/**
|
||||
* SingerSongCount 类,用于存储歌手和歌曲数量信息
|
||||
* 这个类可能用于统计或展示每位歌手的歌曲数量
|
||||
*/
|
||||
class SingerSongCount {
|
||||
// 类定义结束,这里可以添加属性和方法来存储和操作歌手及其歌曲数量
|
||||
|
||||
var total: Int = 0
|
||||
var today: Int = 0
|
||||
var yesterday: Int = 0
|
||||
var week: Int = 0
|
||||
var month: Int = 0
|
||||
var already: Int = 0
|
||||
|
||||
/* total
|
||||
string
|
||||
总数
|
||||
必需
|
||||
today
|
||||
string
|
||||
今天
|
||||
必需
|
||||
yesterday
|
||||
string
|
||||
昨天
|
||||
必需
|
||||
week
|
||||
string
|
||||
本周
|
||||
必需
|
||||
month
|
||||
string
|
||||
本月
|
||||
必需
|
||||
already
|
||||
string
|
||||
已点*/
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
class SongPlaylist {
|
||||
|
||||
var count: Int = 0
|
||||
var lists: List<SongPlaylistBean> = ArrayList()
|
||||
|
||||
class SongPlaylistBean {
|
||||
|
||||
var id: Int = 0
|
||||
var room_id :String =""
|
||||
var user_id: String = ""
|
||||
var singer_song_id: String = ""
|
||||
var status:String =""
|
||||
var sort: Int = 0
|
||||
var boss_nickname: String = ""
|
||||
var song_name: String = ""
|
||||
var gift_id: String = ""
|
||||
var gift_num: String = ""
|
||||
var createtime: String = ""
|
||||
var gift_name: String = ""
|
||||
var gift_price: String = ""
|
||||
var base_image: String = ""
|
||||
var singer_nickname: String = ""
|
||||
|
||||
}
|
||||
|
||||
/* id
|
||||
string 列表ID
|
||||
|
||||
user_id
|
||||
string
|
||||
歌手ID
|
||||
|
||||
song_name
|
||||
string
|
||||
歌曲名
|
||||
|
||||
gift_id
|
||||
string
|
||||
礼物ID
|
||||
|
||||
gift_num
|
||||
string
|
||||
礼物数量
|
||||
|
||||
createtime
|
||||
string
|
||||
添加时间
|
||||
|
||||
gift_name
|
||||
string
|
||||
礼物名称
|
||||
|
||||
gift_price
|
||||
string
|
||||
礼物价格
|
||||
|
||||
base_image
|
||||
string
|
||||
礼物图片
|
||||
|
||||
nickname
|
||||
string
|
||||
歌手昵称*/
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.xscm.moduleutil.bean
|
||||
|
||||
/**
|
||||
*com.xscm.moduleutil.bean
|
||||
*qx
|
||||
*2025/11/8
|
||||
*
|
||||
*/
|
||||
class TableCellData {
|
||||
var title: String = ""
|
||||
var color: String = ""
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
package com.xscm.moduleutil.bean;
|
||||
|
||||
import com.chad.library.adapter.base.entity.MultiItemEntity;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
import com.xscm.moduleutil.bean.room.FriendInfo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author qx
|
||||
* @data 2025/6/3
|
||||
* @description: 个人信息,点击我的获取
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class UserInfo extends BaseEvent implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public static final String FEMALE = "2";
|
||||
public static final String MALE = "1";
|
||||
private int id;
|
||||
private int user_id = 0; //用户id
|
||||
private String user_code;//用户id码
|
||||
private String avatar;//头像
|
||||
private String nickname;//昵称
|
||||
private int sex;//性别 1男 2女
|
||||
private List<String> icon;//等级图标数组
|
||||
private int follow_num;//关注数
|
||||
private int fans_num;//粉丝数
|
||||
private int look_me_num; //被查看次数,需要魅力等级20以上才能查看
|
||||
private int charm_level; //魅力等级
|
||||
private int is_use_code; //是否是靓号 0否 1是
|
||||
private String tencent_im;
|
||||
private String jia_jia;//坐骑
|
||||
private int is_in_pit;//是否在麦上,1在0不在
|
||||
private int is_open_live_remind;//是否设置开播提醒
|
||||
private String birthday;//生日
|
||||
private String profile = "";//简介
|
||||
private String home_bgimages;//背景图片
|
||||
private int is_follow;//是否关注
|
||||
private List<UserTagBean> tag_list;
|
||||
private List<GiftWall> gift_wall;
|
||||
private int age;//年龄
|
||||
private String is_room;
|
||||
private String dress;//头像框
|
||||
private String chat_bubble;//聊天气泡
|
||||
private String charm;//魅力值
|
||||
private String room_id;
|
||||
private String guild = "";//公会名称
|
||||
private String is_mute;//禁言状态 0否 1是
|
||||
private String is_mute_pit;//禁麦状态 0否 1是
|
||||
private String is_manager;//是否是管理员 0否 1是
|
||||
private String is_host;//是否是主持 0否 1是
|
||||
private String is_room_owner;//是否是房主 0否 1是
|
||||
private String pit_number;//在点击麦上用户的时候使用
|
||||
private String auction_id;//在拍卖中的拍卖序号
|
||||
private int auth;//是否实名 1:实名 0:未实名
|
||||
private String red_status;
|
||||
private String gift_num;
|
||||
|
||||
private int is_can_chat;//是否可以私聊,1:可以,0:不可以
|
||||
private int can_chat_money;//需要充值的金额
|
||||
|
||||
private RelationshipBean qinmi;
|
||||
private RelationshipBean zhenai;
|
||||
|
||||
private int heartId; // "heartId": 4,
|
||||
private int heartNum; //
|
||||
private String red_num;
|
||||
private String ta;
|
||||
|
||||
private String nobility_image;//贵族图标
|
||||
private String nickname_color = "";//昵称颜色
|
||||
private String mic_cycle;//麦圈
|
||||
private String is_hide;//0不能设置,1:可以设置
|
||||
private String hide_status;//0-取消隐身,1-设置隐身
|
||||
|
||||
private String enter_image;//爵位飘屏的背景
|
||||
private String enter_text;//爵位飘屏的文字
|
||||
private int singer_status;//歌手认证状态0-待审核,1-通过,2-拒绝 -1:未认证
|
||||
private int singer_level;//歌手等级
|
||||
private CpInfo cp_info;
|
||||
private int market_value;//身价
|
||||
private String market_value_coin="";//身价配置 多少金币数
|
||||
private String market_value_market="";//身价配置 多少身价数
|
||||
|
||||
private String sign_value;
|
||||
private String sign_id;
|
||||
|
||||
private Master master;
|
||||
private int is_online;//是否在线 : 1在线 2离线
|
||||
|
||||
@Data
|
||||
public static class Master implements Serializable {
|
||||
private String user_id;
|
||||
private String nickname;
|
||||
private String avatar;
|
||||
}
|
||||
|
||||
/*"cp_info": {
|
||||
"name": "string",
|
||||
"user_id1": "string",
|
||||
"user_id2": "string",
|
||||
"level": "string",
|
||||
"exp": "string",
|
||||
"pendant": "string",
|
||||
"direction": "string",
|
||||
|
||||
}*/
|
||||
|
||||
@Data
|
||||
public static class CpInfo implements Serializable, MultiItemEntity {
|
||||
private int id;
|
||||
private int user_id1;
|
||||
private int user_id2;
|
||||
private int status;
|
||||
|
||||
private long createtime;
|
||||
|
||||
public String name = "-1";
|
||||
public String level = "-1";
|
||||
public String exp = "-1";
|
||||
public String pendant = "-1";
|
||||
public String direction = "-1";
|
||||
public UserInfo1 user_info1;
|
||||
public UserInfo2 user_info2;
|
||||
|
||||
@Override
|
||||
public int getItemType() {
|
||||
if (name != null && !name.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class UserInfo1 implements Serializable {
|
||||
public String user_id;
|
||||
public String nickname;
|
||||
public String avatar;
|
||||
public String dress;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class UserInfo2 implements Serializable {
|
||||
public String user_id;
|
||||
public String nickname;
|
||||
public String avatar;
|
||||
public String dress;
|
||||
}
|
||||
/*"user_info1": {
|
||||
"user_id": "string",
|
||||
"nickname": "string",
|
||||
"avatar": "string",
|
||||
"dress": "string"
|
||||
},
|
||||
"user_info2": {
|
||||
"user_id": "string",
|
||||
"nickname": "string",
|
||||
"avatar": "string",
|
||||
"dress": "string"
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
// @Data
|
||||
// public static class TagList{
|
||||
// private String id;
|
||||
// private String tag_name;
|
||||
// }
|
||||
@Data
|
||||
public static class GiftWall implements Serializable {
|
||||
private String gift_name;
|
||||
private String total;
|
||||
|
||||
private List<SendUserInfo> send_user_info;
|
||||
|
||||
@Data
|
||||
public static class SendUserInfo implements Serializable {
|
||||
private String nickname;
|
||||
private String avatar;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
package com.xscm.moduleutil.dialog;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.xscm.moduleutil.R;
|
||||
import com.xscm.moduleutil.color.ThemeableDrawableUtils;
|
||||
import com.xscm.moduleutil.utils.ColorManager;
|
||||
|
||||
public class BaseCpDialog extends Dialog {
|
||||
|
||||
private String title;
|
||||
private String message;
|
||||
private String positiveButtonText;
|
||||
private String negativeButtonText;
|
||||
private View.OnClickListener positiveButtonClickListener;
|
||||
private View.OnClickListener negativeButtonClickListener;
|
||||
private boolean isCountdownEnabled = false; // 是否启用倒计时
|
||||
private int countdownSeconds = 0; // 倒计时秒数
|
||||
private CountDownTimer countDownTimer; // 倒计时对象
|
||||
|
||||
|
||||
public BaseCpDialog(Context context, String title, String message,
|
||||
String positiveButtonText, String negativeButtonText,
|
||||
View.OnClickListener positiveButtonClickListener,
|
||||
View.OnClickListener negativeButtonClickListener,
|
||||
boolean isCountdownEnabled, int countdownSeconds) {
|
||||
super(context);
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
this.positiveButtonText = positiveButtonText;
|
||||
this.negativeButtonText = negativeButtonText;
|
||||
this.positiveButtonClickListener = positiveButtonClickListener;
|
||||
this.negativeButtonClickListener = negativeButtonClickListener;
|
||||
this.isCountdownEnabled = isCountdownEnabled;
|
||||
this.countdownSeconds = countdownSeconds;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
window.setGravity(Gravity.CENTER); // 居中显示
|
||||
window.setBackgroundDrawableResource(R.drawable.bg_r16_fff); // 透明背景
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.dialog_confirm);
|
||||
init();
|
||||
// 动态设置背景
|
||||
// getWindow().setBackgroundDrawableResource(R.drawable.bg_r16_fff);
|
||||
|
||||
// 初始化视图
|
||||
TextView tvTitle = findViewById(R.id.tv_title);
|
||||
TextView tvMessage = findViewById(R.id.tv_message);
|
||||
Button btnPositive = findViewById(R.id.btn_positive);
|
||||
Button btnNegative = findViewById(R.id.btn_negative);
|
||||
@SuppressLint({"MissingInflatedId", "LocalSuppress"})
|
||||
ConstraintLayout rootView =(ConstraintLayout) findViewById(R.id.root_view);
|
||||
|
||||
// 设置文本
|
||||
tvTitle.setText(title);
|
||||
tvMessage.setText(message);
|
||||
btnPositive.setText(positiveButtonText);
|
||||
btnNegative.setText(negativeButtonText);
|
||||
|
||||
// 设置点击监听器
|
||||
btnPositive.setOnClickListener(v -> {
|
||||
isCountdownCancelled = true; // 标记倒计时被取消
|
||||
if (countDownTimer != null) {
|
||||
countDownTimer.cancel(); // 取消倒计时
|
||||
countDownTimer = null;
|
||||
}
|
||||
if (positiveButtonClickListener != null) {
|
||||
positiveButtonClickListener.onClick(v);
|
||||
}
|
||||
dismiss();
|
||||
});
|
||||
|
||||
// 判断是否需要显示取消按钮
|
||||
if (negativeButtonText != null && !negativeButtonText.isEmpty()) {
|
||||
btnNegative.setText(negativeButtonText);
|
||||
btnNegative.setVisibility(View.VISIBLE);
|
||||
|
||||
btnNegative.setOnClickListener(v -> {
|
||||
if (negativeButtonClickListener != null) {
|
||||
negativeButtonClickListener.onClick(v);
|
||||
}
|
||||
dismiss();
|
||||
});
|
||||
|
||||
// 倒计时逻辑
|
||||
if (isCountdownEnabled && countdownSeconds > 0) {
|
||||
startCountdown(btnNegative);
|
||||
}
|
||||
} else {
|
||||
// 隐藏取消按钮
|
||||
btnNegative.setVisibility(View.GONE);
|
||||
}
|
||||
// 倒计时逻辑
|
||||
if (isCountdownEnabled && countdownSeconds > 0) {
|
||||
startCountdown(btnNegative);
|
||||
}
|
||||
|
||||
ThemeableDrawableUtils.setThemeableRoundedBackground(btnPositive, ColorManager.getInstance().getPrimaryColorInt(), 53);
|
||||
btnPositive.setTextColor(ColorManager.getInstance().getButtonColorInt());
|
||||
|
||||
// 找到根布局并应用动画
|
||||
|
||||
// if (rootView != null) {
|
||||
// Animation slideDown = AnimationUtils.loadAnimation(context, R.anim.slide_down);
|
||||
// Animation shake = AnimationUtils.loadAnimation(context, R.anim.shake);
|
||||
//
|
||||
// rootView.startAnimation(slideDown);
|
||||
// rootView.startAnimation(shake);
|
||||
// }
|
||||
}
|
||||
private boolean isCountdownCancelled = false; // 添加标志位
|
||||
private void startCountdown(Button btnNegative) {
|
||||
countDownTimer = new CountDownTimer(countdownSeconds * 1000L, 1000) {
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
int secondsLeft = (int) (millisUntilFinished / 1000);
|
||||
btnNegative.setText(negativeButtonText + " (" + secondsLeft + "s)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
// 检查是否被主动取消
|
||||
if (!isCountdownCancelled) {
|
||||
btnNegative.setText(negativeButtonText);
|
||||
if (negativeButtonClickListener != null) {
|
||||
negativeButtonClickListener.onClick(btnNegative); // 自动触发取消
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
@Override
|
||||
public void dismiss() {
|
||||
if (countDownTimer != null) {
|
||||
countDownTimer.cancel(); // 取消倒计时
|
||||
countDownTimer = null;
|
||||
}
|
||||
super.dismiss();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.xscm.moduleutil.diff
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.xscm.moduleutil.bean.CircleListBean
|
||||
|
||||
|
||||
class CircleListDiffCallback(
|
||||
private val oldList: List<CircleListBean>?,
|
||||
private val newList: List<CircleListBean>?
|
||||
) :
|
||||
DiffUtil.Callback() {
|
||||
override fun getOldListSize(): Int {
|
||||
return oldList?.size ?: 0
|
||||
}
|
||||
|
||||
override fun getNewListSize(): Int {
|
||||
return newList?.size ?: 0
|
||||
}
|
||||
|
||||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
return oldList!![oldItemPosition].id == newList!![newItemPosition].id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
val oldItem = oldList!![oldItemPosition]
|
||||
val newItem = newList!![newItemPosition]
|
||||
|
||||
// 判断核心数据是否一致(排除动态字段)
|
||||
if (!equalsStr(oldItem.nickname, newItem.nickname)) return false
|
||||
if (!equalsStr(oldItem.avatar, newItem.avatar)) return false
|
||||
if (!equalsStr(oldItem.content, newItem.content)) return false
|
||||
if (oldItem.is_like != newItem.is_like) return false
|
||||
if (oldItem.sex != newItem.sex) return false
|
||||
if (!equalsStr(oldItem.images, newItem.images)) return false
|
||||
|
||||
// 动态字段不参与整体比较(让 getChangePayload 控制)
|
||||
return equalsStr(oldItem.rewards_num, newItem.rewards_num)
|
||||
&& equalsStr(oldItem.like_num, newItem.like_num)
|
||||
&& equalsStr(oldItem.comment_num, newItem.comment_num)
|
||||
// && equalsStr(oldItem.read_num, newItem.read_num)
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
|
||||
val oldItem = oldList!![oldItemPosition]
|
||||
val newItem = newList!![newItemPosition]
|
||||
|
||||
val diff = Bundle()
|
||||
|
||||
if (!equalsStr(oldItem.rewards_num, newItem.rewards_num)) {
|
||||
diff.putString("rewards_num", newItem.rewards_num)
|
||||
}
|
||||
if (!equalsStr(oldItem.like_num, newItem.like_num)) {
|
||||
diff.putString("like_num", newItem.like_num)
|
||||
diff.putInt("is_like",newItem.is_like)
|
||||
}
|
||||
if (!equalsStr(oldItem.comment_num, newItem.comment_num)) {
|
||||
diff.putString("comment_num", newItem.comment_num)
|
||||
}
|
||||
// if (!equalsStr(oldItem.read_num, newItem.read_num)) {
|
||||
// diff.putString("read_num", newItem.read_num)
|
||||
// }
|
||||
|
||||
return if (diff.size() == 0) null else diff
|
||||
}
|
||||
|
||||
private fun equalsStr(a: String?, b: String?): Boolean {
|
||||
if (a == null && b == null) return true
|
||||
if (a == null || b == null) return false
|
||||
return a == b
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.xscm.moduleutil.enumType
|
||||
|
||||
/**
|
||||
* 房间类型枚举
|
||||
* 对应 type_id 含义:
|
||||
* 2-拍卖(真爱拍小黑屋);1/3/4/8-交友;6-小黑屋;7-互娱
|
||||
*/
|
||||
enum class RoomType(
|
||||
val description: String, // 房间类型描述
|
||||
private vararg val typeIds: Int // 该类型对应的所有 type_id(支持多个)
|
||||
) {
|
||||
// 枚举常量:名称(描述, 对应的type_id)
|
||||
// SINGING_PK("点唱(pk)", 1),
|
||||
AUCTION("拍卖(真爱拍小黑屋)", 2),
|
||||
DATING("交友", 1,3, 4, 8), // 1、3、4、8 均对应交友
|
||||
BLACK_ROOM("小黑屋", 6),
|
||||
JUKEBOX("点唱", 9),
|
||||
MUTUAL_ENTERTAINMENT("互娱", 7),
|
||||
SIGN_CONTRACT("签约", 10);
|
||||
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 根据 type_id 字符串获取对应的枚举实例
|
||||
* @param typeIdStr 房间类型字符串(如 "1"、"3")
|
||||
* @return 匹配的 RoomType,若无效则返回 null
|
||||
*/
|
||||
fun fromTypeId(typeIdStr: String?): RoomType? {
|
||||
if (typeIdStr.isNullOrBlank()) return null
|
||||
val typeId = try {
|
||||
typeIdStr.toInt() // 转换为 Int(处理数字字符串)
|
||||
} catch (e: NumberFormatException) {
|
||||
return null // 非数字字符串视为无效
|
||||
}
|
||||
// 遍历所有枚举,匹配 type_id
|
||||
return values().find { typeId in it.typeIds }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.xscm.moduleutil.event;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class CabinEvent extends BaseEvent {
|
||||
private boolean joined;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.xscm.moduleutil.event;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
public class GiftDoubleClickEvent extends BaseEvent {
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.xscm.moduleutil.event;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
public class LogOutEvent extends BaseEvent {
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.xscm.moduleutil.event;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
*@author qx
|
||||
*@data 2025/6/24
|
||||
*@description: 背景音乐
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MusicEvent extends BaseEvent {
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.xscm.moduleutil.event;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class PlazaEvent extends BaseEvent {
|
||||
public static final int DELETE_ZONE = 1009;
|
||||
public static final int MODIFY_ZONE = 1008;
|
||||
public static final int ADD_ZONE = 1007;
|
||||
private int msgId;
|
||||
private int type;//DELETE_ZONE : 删除 MODIFY_ZONE : 修改 ADD_ZONE : 新增
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.xscm.moduleutil.event;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
public class RoomOutEvent extends BaseEvent {
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.xscm.moduleutil.event;
|
||||
|
||||
import com.xscm.moduleutil.BaseEvent;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class RoomOwnerLeaveEvent extends BaseEvent {
|
||||
private String room_id;
|
||||
private String user_id;
|
||||
private String emchat_username;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.xscm.moduleutil.listener
|
||||
|
||||
import com.xscm.moduleutil.bean.RoomGiftData
|
||||
import com.xscm.moduleutil.bean.RoomMessageEvent
|
||||
|
||||
/**
|
||||
* 这是cp的监听器,方便在各个模块中调用
|
||||
*/
|
||||
interface CPListener {
|
||||
/**
|
||||
* 发送CP消息的处理函数
|
||||
* @param gitData 礼物数据信息,包含房间礼物相关的数据
|
||||
*/
|
||||
fun onSendCpMsg(gitData: RoomGiftData)
|
||||
|
||||
/**
|
||||
* 接收房间消息事件的处理函数
|
||||
* @param roomMessageEvent 房间消息事件对象,包含消息相关的所有信息
|
||||
*/
|
||||
fun onReceiveMsg(roomMessageEvent: RoomMessageEvent)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.xscm.moduleutil.utils;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
*@author qx
|
||||
*@data 2025/9/10
|
||||
*@description: 防止重复点击的工具类
|
||||
*/
|
||||
public class ClickUtils {
|
||||
private static final long DEFAULT_CLICK_INTERVAL = 500;
|
||||
private static final SparseArray<Long> lastClickTimes = new SparseArray<>();
|
||||
|
||||
public static boolean isFastDoubleClick(View view) {
|
||||
return isFastDoubleClick(view, DEFAULT_CLICK_INTERVAL);
|
||||
}
|
||||
|
||||
public static boolean isFastDoubleClick(View view, long interval) {
|
||||
long currentTime = SystemClock.elapsedRealtime();
|
||||
int viewId = view.getId();
|
||||
Long lastClickTime = lastClickTimes.get(viewId);
|
||||
if (lastClickTime != null && currentTime - lastClickTime < interval) {
|
||||
return true;
|
||||
}
|
||||
lastClickTimes.put(viewId, currentTime);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 新增:清理所有点击记录
|
||||
public static void clearAllClickRecords() {
|
||||
lastClickTimes.clear();
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package com.xscm.moduleutil.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.blankj.utilcode.util.LogUtils;
|
||||
import com.xscm.moduleutil.R;
|
||||
import com.xscm.moduleutil.utils.logger.Logger;
|
||||
import com.xscm.moduleutil.widget.AvatarFrameView;
|
||||
|
||||
|
||||
/**
|
||||
* 描述 设置中的用户头像
|
||||
*/
|
||||
public class MeHeadView extends ConstraintLayout {
|
||||
private ImageView mRiv;
|
||||
private AvatarFrameView mIvFrame;
|
||||
private ImageView mIvSex;
|
||||
private ImageView mIvOnline;
|
||||
private ImageView iv_frame_bg;
|
||||
private ImageView iv_master_bg;
|
||||
|
||||
public MeHeadView(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public MeHeadView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public MeHeadView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
LayoutInflater.from(context).inflate(R.layout.me_view_decoration_head, this, true);
|
||||
mRiv = findViewById(R.id.riv);
|
||||
mIvFrame = findViewById(R.id.iv_frame);
|
||||
mIvSex = findViewById(R.id.iv_sex);
|
||||
mIvOnline = findViewById(R.id.iv_online);
|
||||
iv_frame_bg = findViewById(R.id.iv_frame_bg);
|
||||
iv_master_bg = findViewById(R.id.iv_master_bg);
|
||||
mIvSex.setVisibility(GONE);
|
||||
}
|
||||
|
||||
public void setData(String headPicture, String framePicture, String nobilityImage) {
|
||||
LogUtils.e(headPicture, framePicture, nobilityImage);
|
||||
if (!TextUtils.isEmpty(headPicture)) {
|
||||
ImageUtils.loadHead(headPicture, mRiv);
|
||||
}
|
||||
if (TextUtils.isEmpty(framePicture)) {
|
||||
mIvFrame.setVisibility(GONE);
|
||||
} else {
|
||||
mIvFrame.setVisibility(VISIBLE);
|
||||
mIvFrame.setSource(framePicture, 1);
|
||||
}
|
||||
|
||||
if (nobilityImage != null && !TextUtils.isEmpty(nobilityImage)) {
|
||||
iv_frame_bg.setVisibility(VISIBLE);
|
||||
ImageUtils.loadRoomItem(nobilityImage, iv_frame_bg);
|
||||
} else {
|
||||
iv_frame_bg.setVisibility(GONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setMaster(String headPicture) {
|
||||
if (!TextUtils.isEmpty(headPicture)) {
|
||||
ImageUtils.loadHead(headPicture, mRiv);
|
||||
}
|
||||
|
||||
iv_master_bg.setVisibility(VISIBLE);
|
||||
iv_master_bg.setImageResource(R.mipmap.icon_master);
|
||||
}
|
||||
|
||||
public void setOnline(boolean isOnline) {
|
||||
mIvOnline.setVisibility(VISIBLE);
|
||||
mIvOnline.setImageResource(isOnline ? R.mipmap.me_online_icon : R.mipmap.me_icon_unchecked);
|
||||
}
|
||||
|
||||
public void setSex(int sex, String headPicture, String dress) {
|
||||
if (!TextUtils.isEmpty(headPicture)) {
|
||||
ImageUtils.loadHead(headPicture, mRiv);
|
||||
}
|
||||
if (TextUtils.isEmpty(dress)) {
|
||||
mIvFrame.setVisibility(GONE);
|
||||
} else {
|
||||
mIvFrame.setVisibility(VISIBLE);
|
||||
mIvFrame.setSource(dress, 1);
|
||||
}
|
||||
mIvSex.setVisibility(VISIBLE);
|
||||
mIvSex.setImageResource(sex == 1 ? R.mipmap.nan : R.mipmap.nv);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置头像,性别,头像框,贵族
|
||||
* @param sex
|
||||
* @param headPicture
|
||||
* @param framePicture
|
||||
* @param nobilityImage
|
||||
*/
|
||||
public void setAll(int sex,String headPicture, String framePicture, String nobilityImage) {
|
||||
if (!TextUtils.isEmpty(headPicture)) {
|
||||
ImageUtils.loadHead(headPicture, mRiv);
|
||||
}
|
||||
if (TextUtils.isEmpty(framePicture)) {
|
||||
mIvFrame.setVisibility(GONE);
|
||||
} else {
|
||||
mIvFrame.setVisibility(VISIBLE);
|
||||
mIvFrame.setSource(framePicture, 1);
|
||||
}
|
||||
|
||||
mIvSex.setImageResource(sex == 1 ? R.mipmap.nan : R.mipmap.nv);
|
||||
if (nobilityImage != null && !TextUtils.isEmpty(nobilityImage)) {
|
||||
iv_frame_bg.setVisibility(VISIBLE);
|
||||
ImageUtils.loadRoomItem(nobilityImage, iv_frame_bg);
|
||||
} else {
|
||||
iv_frame_bg.setVisibility(GONE);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,939 +0,0 @@
|
||||
package com.xscm.moduleutil.utils.roomview;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationSet;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.blankj.utilcode.util.LogUtils;
|
||||
import com.tencent.qgame.animplayer.AnimConfig;
|
||||
import com.tencent.qgame.animplayer.AnimView;
|
||||
import com.tencent.qgame.animplayer.inter.IAnimListener;
|
||||
import com.xscm.moduleutil.R;
|
||||
import com.xscm.moduleutil.utils.ImageUtils;
|
||||
import com.xscm.moduleutil.widget.CircularImage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
/**
|
||||
* 项目名称:羽声语音
|
||||
* 时间:2025/11/24 9:50
|
||||
* 用途:
|
||||
*/
|
||||
public class RoomCPView extends FrameLayout {
|
||||
|
||||
private AnimView anim_cp;
|
||||
|
||||
private boolean isLoadEffect = false;
|
||||
private boolean isShow = true; // 是否开启特效
|
||||
private ReentrantLock lock = new ReentrantLock();
|
||||
private List<String> animationArray = new ArrayList<>();
|
||||
public ExecutorService queue = Executors.newSingleThreadExecutor();
|
||||
private Context mContext;
|
||||
private boolean isOnece;
|
||||
|
||||
private CircularImage room_cp_head1;
|
||||
private CircularImage room_cp_head2;
|
||||
private TextView room_cp_name1, room_cp_name2;
|
||||
private LinearLayout avatarContainer1;
|
||||
private ConstraintLayout avatarsParentContainer;
|
||||
|
||||
// 动画队列和锁机制
|
||||
private final Queue<AnimationTask> animationQueue = new LinkedList<>();
|
||||
private boolean isAnimationRunning = false;
|
||||
private final Object animationLock = new Object();
|
||||
|
||||
// 下载任务缓存
|
||||
private final Queue<DownloadTask> downloadQueue = new LinkedList<>();
|
||||
private boolean isDownloadRunning = false;
|
||||
private final Object downloadLock = new Object();
|
||||
|
||||
private String currPlayPath = "";
|
||||
|
||||
public void setQueue(ExecutorService queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
public RoomCPView(@NonNull Context context) {
|
||||
super(context);
|
||||
this.mContext = context;
|
||||
init();
|
||||
}
|
||||
|
||||
public RoomCPView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this.mContext = context;
|
||||
init();
|
||||
}
|
||||
|
||||
public RoomCPView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
this.mContext = context;
|
||||
init();
|
||||
}
|
||||
|
||||
public RoomCPView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
this.mContext = context;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
isLoadEffect = false;
|
||||
|
||||
initView();
|
||||
|
||||
// 设置动画监听器
|
||||
setupAnimListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置动画监听器
|
||||
*/
|
||||
private void setupAnimListener() {
|
||||
if (anim_cp != null) {
|
||||
anim_cp.setAnimListener(new IAnimListener() {
|
||||
@Override
|
||||
public void onVideoDestroy() {
|
||||
LogUtils.e("onVideoDestroy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoComplete() {
|
||||
LogUtils.e("onVideoComplete");
|
||||
// 确保所有UI操作在主线程中执行
|
||||
post(() -> {
|
||||
if (anim_cp != null) {
|
||||
// 停止头像动画
|
||||
stopAvatarAnimation();
|
||||
|
||||
// 隐藏动画视图和头像
|
||||
anim_cp.setVisibility(View.GONE);
|
||||
avatarContainer1.setVisibility(View.GONE);
|
||||
|
||||
if (isOnece) {
|
||||
return;
|
||||
}
|
||||
// 通知播放完成
|
||||
notifyPlaybackComplete();
|
||||
loadStartAnimation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoRender(int i, @Nullable AnimConfig animConfig) {
|
||||
// LogUtils.e("onVideoRender", i, animConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoStart() {
|
||||
LogUtils.e("onVideoStart");
|
||||
// 确保所有UI操作在主线程中执行
|
||||
post(() -> {
|
||||
// 动画开始,显示视图和头像
|
||||
setVisibility(View.VISIBLE);
|
||||
anim_cp.setVisibility(View.VISIBLE);
|
||||
avatarContainer1.setVisibility(View.VISIBLE);
|
||||
|
||||
|
||||
// 启动头像上下浮动动画
|
||||
// startAvatarFloatAnimation();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) {
|
||||
LogUtils.e("onVideoConfigReady", animConfig);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int i, @Nullable String s) {
|
||||
LogUtils.e("onFailed", s);
|
||||
// 确保所有UI操作在主线程中执行
|
||||
post(() -> {
|
||||
// 动画失败,隐藏视图
|
||||
setVisibility(View.GONE);
|
||||
anim_cp.setVisibility(View.GONE);
|
||||
// 继续播放下一个
|
||||
loadStartAnimation();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(getContext()).inflate(R.layout.room_cp_vip_view, this, true);
|
||||
anim_cp = findViewById(R.id.anim_cp);
|
||||
room_cp_head1 = findViewById(R.id.room_cp_head1);
|
||||
room_cp_head2 = findViewById(R.id.room_cp_head2);
|
||||
room_cp_name1 = findViewById(R.id.room_cp_name1);
|
||||
room_cp_name2 = findViewById(R.id.room_cp_name2);
|
||||
|
||||
// 获取头像的父布局
|
||||
avatarContainer1 = findViewById(R.id.ll_head);
|
||||
|
||||
// 获取包含两个头像的父 LinearLayout
|
||||
avatarsParentContainer = (ConstraintLayout) avatarContainer1.getParent();
|
||||
|
||||
// // 初始状态隐藏头像和名称
|
||||
// room_cp_head1.setVisibility(View.GONE);
|
||||
// room_cp_head2.setVisibility(View.GONE);
|
||||
// room_cp_name1.setVisibility(View.GONE);
|
||||
// room_cp_name2.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setCPTextData(String room_head1, String room_head2, String room_cp_name1, String room_cp_name2) {
|
||||
ImageUtils.loadHeadCC(room_head1, room_cp_head1);
|
||||
ImageUtils.loadHeadCC(room_head2, room_cp_head2);
|
||||
this.room_cp_name1.setText(room_cp_name1);
|
||||
this.room_cp_name2.setText(room_cp_name2);
|
||||
}
|
||||
|
||||
private void loadStartAnimation() {
|
||||
if (!isShow) {
|
||||
// isshow 为是否开启特效 如果未开启则return
|
||||
return;
|
||||
}
|
||||
|
||||
String animationPath = null;
|
||||
|
||||
// list加锁
|
||||
lock.lock();
|
||||
try {
|
||||
// 如果list长度大于0
|
||||
if (!animationArray.isEmpty()) {
|
||||
// 动画路径则赋值,取list中的第一个数据
|
||||
animationPath = animationArray.get(0);
|
||||
// 移除list的第一条数据
|
||||
animationArray.remove(0);
|
||||
isLoadEffect = true;
|
||||
} else {
|
||||
isLoadEffect = false;
|
||||
// 队列为空,释放资源但不销毁视图
|
||||
post(() -> {
|
||||
destroyEffectView();
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
// 解锁
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
if (isLoadEffect && animationPath != null && !TextUtils.isEmpty(animationPath)) {
|
||||
String finalAnimationPath = animationPath;
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// 处理MP4动画文件(可能是网络URL)
|
||||
handleMP4File(finalAnimationPath, new DownloadCallback() {
|
||||
@Override
|
||||
public void onSuccess(String localPath) {
|
||||
post(() -> {
|
||||
// 设置MP4动画文件
|
||||
currPlayPath = localPath;
|
||||
// 启动从底部弹起动画
|
||||
startBottomUpAnimation();
|
||||
|
||||
// 开始播放动画
|
||||
anim_cp.setLoop(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
LogUtils.e("MP4下载或播放失败: " + error);
|
||||
// 处理失败情况,继续播放下一个
|
||||
post(() -> {
|
||||
lock.lock();
|
||||
try {
|
||||
isLoadEffect = false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
loadStartAnimation();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CP特效进来
|
||||
*
|
||||
* @param room_head1 头像1
|
||||
* @param room_head2 头像2
|
||||
* @param room_name1 名称1
|
||||
* @param room_name2 名称2
|
||||
* @param mp4Path MP4动画文件路径
|
||||
*/
|
||||
public void displayEffectView(String room_head1, String room_head2, String room_name1, String room_name2, String mp4Path) {
|
||||
// 确保视图已初始化
|
||||
reinitView();
|
||||
|
||||
// 设置CP数据,但不显示头像
|
||||
setCPTextData(room_head1, room_head2, room_name1, room_name2);
|
||||
|
||||
// 确保头像初始为隐藏状态
|
||||
// room_cp_head1.setVisibility(View.GONE);
|
||||
// room_cp_head2.setVisibility(View.GONE);
|
||||
// room_cp_name1.setVisibility(View.GONE);
|
||||
// room_cp_name2.setVisibility(View.GONE);
|
||||
|
||||
// 确保视图可见
|
||||
setVisibility(View.VISIBLE);
|
||||
|
||||
// 检查队列是否已初始化
|
||||
if (queue == null) {
|
||||
queue = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
queue.execute(new Runnable() {
|
||||
@SuppressLint("CheckResult")
|
||||
@Override
|
||||
public void run() {
|
||||
// 如果mp4Path不存在return
|
||||
if (mp4Path == null || mp4Path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 将mp4Path链接转为小写
|
||||
String playImage = mp4Path;
|
||||
String pathExtension = getFileExtension(playImage).toLowerCase();
|
||||
|
||||
// 判定礼物的后缀是否为svga或者mp4如果非这两种 则return
|
||||
if (!("svga".equals(pathExtension) || "mp4".equals(pathExtension))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 锁住list
|
||||
lock.lock();
|
||||
try {
|
||||
// 添加动画数据进list
|
||||
animationArray.add(playImage);
|
||||
|
||||
// 如果没有在加载则开始加载
|
||||
if (!isLoadEffect) {
|
||||
// 更改加载状态标记
|
||||
Observable.timer(2000, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Long>() {
|
||||
@Override
|
||||
public void accept(Long aLong) throws Exception {
|
||||
isLoadEffect = true;
|
||||
loadStartAnimation();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
} finally {
|
||||
// 解锁
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 原始的动画方法,现在只被内部调用
|
||||
*/
|
||||
public void startAnimation(AnimationListener listener) {
|
||||
// 设置进入动画
|
||||
AlphaAnimation fadeIn = new AlphaAnimation(0f, 1f);
|
||||
fadeIn.setDuration(500);
|
||||
fadeIn.setAnimationListener(new Animation.AnimationListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
// 保持显示1秒后开始退出动画
|
||||
postDelayed(() -> {
|
||||
AlphaAnimation fadeOut = new AlphaAnimation(1f, 0f);
|
||||
fadeOut.setDuration(500);
|
||||
fadeOut.setAnimationListener(new Animation.AnimationListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
if (listener != null) {
|
||||
listener.onAnimationEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
}
|
||||
});
|
||||
startAnimation(fadeOut);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
}
|
||||
});
|
||||
startAnimation(fadeIn);
|
||||
}
|
||||
|
||||
public interface AnimationListener {
|
||||
void onAnimationEnd();
|
||||
}
|
||||
|
||||
// 添加播放完成监听接口
|
||||
public interface OnPlaybackCompleteListener {
|
||||
void onPlaybackComplete();
|
||||
}
|
||||
|
||||
// 添加成员变量
|
||||
private List<OnPlaybackCompleteListener> playbackCompleteListeners = new ArrayList<>();
|
||||
|
||||
// 添加监听器管理方法
|
||||
public void addOnPlaybackCompleteListener(OnPlaybackCompleteListener listener) {
|
||||
if (listener != null && !playbackCompleteListeners.contains(listener)) {
|
||||
playbackCompleteListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeOnPlaybackCompleteListener(OnPlaybackCompleteListener listener) {
|
||||
if (listener != null) {
|
||||
playbackCompleteListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearPlaybackCompleteListeners() {
|
||||
playbackCompleteListeners.clear();
|
||||
}
|
||||
|
||||
// 触发播放完成回调的方法
|
||||
private void notifyPlaybackComplete() {
|
||||
for (OnPlaybackCompleteListener listener : new ArrayList<>(playbackCompleteListeners)) {
|
||||
if (listener != null) {
|
||||
listener.onPlaybackComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 动画任务类,用于存储动画所需的数据
|
||||
*/
|
||||
public static class AnimationTask {
|
||||
String room_head1;
|
||||
String room_head2;
|
||||
String room_cp_name1;
|
||||
String room_cp_name2;
|
||||
String mp4Path; // MP4动画文件路径
|
||||
AnimationListener listener;
|
||||
|
||||
AnimationTask(String room_head1, String room_head2, String room_cp_name1, String room_cp_name2, String mp4Path, AnimationListener listener) {
|
||||
this.room_head1 = room_head1;
|
||||
this.room_head2 = room_head2;
|
||||
this.room_cp_name1 = room_cp_name1;
|
||||
this.room_cp_name2 = room_cp_name2;
|
||||
this.mp4Path = mp4Path;
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理MP4文件,如果是网络URL则下载到本地
|
||||
*
|
||||
* @param path 文件路径或URL
|
||||
* @param callback 下载回调
|
||||
*/
|
||||
private void handleMP4File(String path, DownloadCallback callback) {
|
||||
// 判断是否是网络URL
|
||||
if (path != null && (path.startsWith("http://") || path.startsWith("https://"))) {
|
||||
// 是网络URL,需要下载
|
||||
downloadFile(path, callback);
|
||||
} else {
|
||||
// 本地路径,直接使用
|
||||
if (callback != null) {
|
||||
callback.onSuccess(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件到本地
|
||||
*
|
||||
* @param url 下载URL
|
||||
* @param callback 下载回调
|
||||
*/
|
||||
private void downloadFile(String url, DownloadCallback callback) {
|
||||
synchronized (downloadLock) {
|
||||
// 创建下载任务并加入队列
|
||||
DownloadTask task = new DownloadTask(url, callback);
|
||||
downloadQueue.offer(task);
|
||||
|
||||
// 如果当前没有下载任务在执行,则开始下载
|
||||
if (!isDownloadRunning) {
|
||||
processNextDownload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理下一个下载任务
|
||||
*/
|
||||
private void processNextDownload() {
|
||||
synchronized (downloadLock) {
|
||||
if (downloadQueue.isEmpty()) {
|
||||
isDownloadRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
isDownloadRunning = true;
|
||||
DownloadTask currentTask = downloadQueue.poll();
|
||||
|
||||
// 执行下载任务
|
||||
new DownloadAsyncTask(currentTask.callback).execute(currentTask.url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步下载任务
|
||||
*/
|
||||
private class DownloadAsyncTask extends AsyncTask<String, Void, String> {
|
||||
private DownloadCallback callback;
|
||||
private String errorMessage;
|
||||
|
||||
public DownloadAsyncTask(DownloadCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... urls) {
|
||||
String url = urls[0];
|
||||
try {
|
||||
// 获取文件名
|
||||
int lastSlashIndex = url.lastIndexOf('/');
|
||||
String fileName = lastSlashIndex != -1 ? url.substring(lastSlashIndex + 1) : url;
|
||||
int queryIndex = fileName.indexOf("?");
|
||||
if (queryIndex != -1) {
|
||||
fileName = fileName.substring(0, queryIndex);
|
||||
}
|
||||
|
||||
// 创建本地文件
|
||||
File dir = new File(getContext().getCacheDir(), "animations");
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
File file = new File(dir, fileName);
|
||||
|
||||
// 如果文件已存在,直接返回本地路径
|
||||
if (file.exists()) {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
// 下载文件
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.connect();
|
||||
|
||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
errorMessage = "服务器返回HTTP错误代码: " + connection.getResponseCode();
|
||||
return null;
|
||||
}
|
||||
|
||||
InputStream input = connection.getInputStream();
|
||||
FileOutputStream output = new FileOutputStream(file);
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = input.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
output.close();
|
||||
input.close();
|
||||
connection.disconnect();
|
||||
|
||||
return file.getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
errorMessage = "下载失败: " + e.getMessage();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String result) {
|
||||
synchronized (downloadLock) {
|
||||
// 下载完成,处理下一个下载任务
|
||||
processNextDownload();
|
||||
}
|
||||
|
||||
// 通知回调
|
||||
if (callback != null) {
|
||||
if (result != null) {
|
||||
callback.onSuccess(result);
|
||||
} else {
|
||||
callback.onError(errorMessage != null ? errorMessage : "未知错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载任务类
|
||||
*/
|
||||
private static class DownloadTask {
|
||||
String url;
|
||||
DownloadCallback callback;
|
||||
|
||||
DownloadTask(String url, DownloadCallback callback) {
|
||||
this.url = url;
|
||||
this.callback = callback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载回调接口
|
||||
*/
|
||||
private interface DownloadCallback {
|
||||
void onSuccess(String localPath);
|
||||
|
||||
void onError(String error);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
*
|
||||
* @param url 文件URL
|
||||
* @return 文件扩展名
|
||||
*/
|
||||
private String getFileExtension(String url) {
|
||||
if (url != null && url.contains(".")) {
|
||||
return url.substring(url.lastIndexOf(".") + 1);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁特效视图
|
||||
*/
|
||||
public void destroyEffectView() {
|
||||
// 停止头像动画
|
||||
stopAvatarAnimation();
|
||||
|
||||
// 清理监听器
|
||||
clearPlaybackCompleteListeners();
|
||||
|
||||
// 停止动画视图但保留组件以便重用
|
||||
if (anim_cp != null) {
|
||||
anim_cp.stopPlay();
|
||||
anim_cp.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// 隐藏视图但不移除,以便再次使用
|
||||
setVisibility(View.GONE);
|
||||
|
||||
// 清空动画队列
|
||||
lock.lock();
|
||||
try {
|
||||
animationArray.clear();
|
||||
isLoadEffect = false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从底部弹起动画
|
||||
*/
|
||||
private void startBottomUpAnimation() {
|
||||
// 获取父视图的高度,如果为0则使用屏幕高度
|
||||
float parentHeight = 0;
|
||||
if (getParent() != null) {
|
||||
parentHeight = ((View) getParent()).getHeight();
|
||||
}
|
||||
if (parentHeight <= 0) {
|
||||
parentHeight = getResources().getDisplayMetrics().heightPixels;
|
||||
}
|
||||
|
||||
// 设置初始位置在屏幕底部外
|
||||
// setTranslationY(parentHeight);
|
||||
|
||||
// 创建从底部弹起的动画
|
||||
TranslateAnimation bottomUpAnimation = new TranslateAnimation(
|
||||
Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
|
||||
Animation.RELATIVE_TO_PARENT, 1.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
|
||||
bottomUpAnimation.setDuration(2000); // 动画持续时间
|
||||
|
||||
// 创建弹性插值器
|
||||
Interpolator overshootInterpolator = new OvershootInterpolator(0.5f);
|
||||
bottomUpAnimation.setInterpolator(overshootInterpolator);
|
||||
|
||||
// 应用动画
|
||||
startAnimation(bottomUpAnimation);
|
||||
|
||||
// 动画结束后重置位置
|
||||
bottomUpAnimation.setAnimationListener(new Animation.AnimationListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
setVisibility(View.VISIBLE);
|
||||
anim_cp.setVisibility(View.VISIBLE);
|
||||
avatarContainer1.setVisibility(VISIBLE);
|
||||
|
||||
anim_cp.startPlay(new File(currPlayPath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
startAvatarFloatAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
}
|
||||
});
|
||||
avatarsParentContainer.startAnimation(bottomUpAnimation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 头像上下动画
|
||||
*/
|
||||
private void startAvatarFloatAnimation() {
|
||||
// 确保包含两个头像的父布局已初始化
|
||||
if (avatarsParentContainer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 包含两个头像的父布局上下浮动动画
|
||||
AnimationSet avatarsAnimationSet = new AnimationSet(true);
|
||||
// 使用适中的移动距离,确保头像框显示完整
|
||||
TranslateAnimation avatarsFloatUp = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
|
||||
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -0.01f);
|
||||
avatarsFloatUp.setDuration(900); // 增加动画持续时间,使动画更平滑
|
||||
avatarsFloatUp.setRepeatCount(Animation.INFINITE);
|
||||
avatarsFloatUp.setRepeatMode(Animation.REVERSE);
|
||||
|
||||
avatarsAnimationSet.addAnimation(avatarsFloatUp);
|
||||
avatarsParentContainer.startAnimation(avatarsAnimationSet);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止头像动画
|
||||
*/
|
||||
private void stopAvatarAnimation() {
|
||||
if (avatarsParentContainer != null) {
|
||||
avatarsParentContainer.clearAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放动画
|
||||
*/
|
||||
public void stopPlay() {
|
||||
stopAvatarAnimation();
|
||||
if (anim_cp != null) {
|
||||
anim_cp.stopPlay();
|
||||
anim_cp.setVisibility(View.GONE);
|
||||
}
|
||||
setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启或关闭特效视图
|
||||
*
|
||||
* @param isShow 是否显示
|
||||
*/
|
||||
public void openOrCloseEffectViewWith(boolean isShow) {
|
||||
this.isShow = isShow;
|
||||
|
||||
if (anim_cp != null) {
|
||||
anim_cp.stopPlay();
|
||||
anim_cp.setVisibility(View.GONE);
|
||||
}
|
||||
setVisibility(isShow ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载并播放动画
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param playImage 动画URL
|
||||
* @param callback 下载回调
|
||||
*/
|
||||
public void downloadAndPlay(Context context, String playImage, DownloadCallback callback) {
|
||||
String fileName = playImage.substring(playImage.lastIndexOf("/"));
|
||||
String filePath = context.getCacheDir().getAbsolutePath() + fileName;
|
||||
|
||||
LogUtils.e("@@@@@filePath: " + filePath.toString());
|
||||
|
||||
File file = new File(filePath);
|
||||
|
||||
if (!file.exists()) {
|
||||
LogUtils.e("无缓存");
|
||||
// 使用OkHttp进行下载
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Request request = new Request.Builder()
|
||||
.url(playImage)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
LogUtils.e("MP4下载失败: " + e.toString());
|
||||
// 在主线程中回调失败
|
||||
post(() -> {
|
||||
if (callback != null) {
|
||||
callback.onError(e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
if (responseBody != null) {
|
||||
File downloadedFile = new File(filePath);
|
||||
FileOutputStream fos = new FileOutputStream(downloadedFile);
|
||||
fos.write(responseBody.bytes());
|
||||
fos.close();
|
||||
|
||||
// 在主线程中回调成功
|
||||
post(() -> {
|
||||
if (callback != null) {
|
||||
callback.onSuccess(downloadedFile.getAbsolutePath());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 在主线程中回调失败
|
||||
post(() -> {
|
||||
if (callback != null) {
|
||||
callback.onError("Response body is null");
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e("MP4文件保存失败: " + e.getMessage());
|
||||
// 在主线程中回调失败
|
||||
post(() -> {
|
||||
if (callback != null) {
|
||||
callback.onError(e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
LogUtils.e("MP4下载响应失败");
|
||||
// 在主线程中回调失败
|
||||
post(() -> {
|
||||
if (callback != null) {
|
||||
callback.onError("Response not successful: " + response.code());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 文件已存在,直接回调成功
|
||||
if (callback != null) {
|
||||
callback.onSuccess(file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新初始化视图,以便再次播放
|
||||
*/
|
||||
public void reinitView() {
|
||||
if (anim_cp == null) {
|
||||
// 如果动画视图已被销毁,重新初始化
|
||||
initView();
|
||||
|
||||
// 重新设置动画监听器
|
||||
setupAnimListener();
|
||||
}
|
||||
|
||||
// 确保线程池可用
|
||||
if (queue == null || queue.isShutdown()) {
|
||||
queue = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
// 重置状态
|
||||
isLoadEffect = false;
|
||||
isShow = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完全销毁视图,释放所有资源
|
||||
* 当不再需要此视图时调用
|
||||
*/
|
||||
public void completeDestroy() {
|
||||
// 停止头像动画
|
||||
stopAvatarAnimation();
|
||||
|
||||
// 清理监听器
|
||||
clearPlaybackCompleteListeners();
|
||||
|
||||
// 停止并移除动画视图
|
||||
if (anim_cp != null) {
|
||||
anim_cp.stopPlay();
|
||||
removeView(anim_cp);
|
||||
anim_cp = null;
|
||||
}
|
||||
|
||||
// 停止线程池
|
||||
if (queue != null) {
|
||||
queue.shutdown();
|
||||
queue = null;
|
||||
}
|
||||
|
||||
// 隐藏并移除整个视图
|
||||
setVisibility(View.GONE);
|
||||
if (getParent() != null) {
|
||||
((ViewGroup) getParent()).removeView(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.xscm.moduleutil.widget
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
/**
|
||||
* 项目名称:羽声语音
|
||||
* 时间:2025/12/3 9:30
|
||||
* 用途:
|
||||
*/
|
||||
|
||||
|
||||
class CustomViewPager(context: Context, attrs: AttributeSet?) : ViewPager(context, attrs) {
|
||||
|
||||
private var initialX = 0f
|
||||
private var initialY = 0f
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
||||
when (ev.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
// 记录初始触摸点
|
||||
initialX = ev.x
|
||||
initialY = ev.y
|
||||
parent.requestDisallowInterceptTouchEvent(true) // 请求父容器不要拦截事件
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val deltaX = Math.abs(ev.x - initialX)
|
||||
val deltaY = Math.abs(ev.y - initialY)
|
||||
|
||||
// 如果水平滑动距离大于垂直滑动距离,才认为是水平滑动,ViewPager才拦截事件
|
||||
if (deltaX > deltaY && deltaX > 30) { // 30是阈值,可以根据需要调整
|
||||
return super.onInterceptTouchEvent(ev)
|
||||
}
|
||||
// 否则,不拦截,让子视图处理
|
||||
parent.requestDisallowInterceptTouchEvent(true)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev)
|
||||
}
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
package com.xscm.moduleutil.widget;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewAnimationUtils;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.blankj.utilcode.util.ScreenUtils;
|
||||
import com.xscm.moduleutil.utils.BarUtils;
|
||||
|
||||
/**
|
||||
* com.xscm.moduleutil.widget
|
||||
* qx 首页首充好礼的悬浮框
|
||||
* 2025/11/4
|
||||
*/
|
||||
public class DropHomeView extends LinearLayout {
|
||||
|
||||
private int rightMargin = 0;
|
||||
private float lastX, lastY;
|
||||
private int screenWidth;
|
||||
private int screenHeight; // 添加屏幕高度变量
|
||||
|
||||
public DropHomeView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public DropHomeView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public DropHomeView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
void init() {
|
||||
// 初始化屏幕尺寸
|
||||
screenWidth = ScreenUtils.getScreenWidth();
|
||||
screenHeight = ScreenUtils.getScreenHeight();
|
||||
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//设置初始位置
|
||||
int sh = ScreenUtils.getScreenHeight();
|
||||
int sw = ScreenUtils.getScreenWidth();
|
||||
// setBackgroundResource(R.drawable.bg_home_drop_view);
|
||||
int y = (int) (0.6f * sh) - getHeight();//这是设置展示的纵坐标
|
||||
// 确保Y坐标不会超出屏幕范围
|
||||
y = Math.max(0, Math.min(y, sh - getHeight()));
|
||||
// int x = sw - getWidth();//这是靠右边展示的
|
||||
int x=20 ;//这里这只一小的数值,就是靠左展示的
|
||||
setTranslationX(x);
|
||||
setTranslationY(y);
|
||||
}
|
||||
});
|
||||
|
||||
updateSize();
|
||||
mStatusBarHeight = BarUtils.getStatusBarHeight();
|
||||
}
|
||||
/**
|
||||
* 更新屏幕尺寸信息
|
||||
*/
|
||||
protected void updateSize() {
|
||||
ViewGroup viewGroup = (ViewGroup) getParent();
|
||||
if (viewGroup != null) {
|
||||
mScreenWidth = viewGroup.getWidth();
|
||||
mScreenHeight = viewGroup.getHeight();
|
||||
} else {
|
||||
// 如果父视图为空,使用屏幕的实际宽度和高度
|
||||
mScreenWidth = getResources().getDisplayMetrics().widthPixels;
|
||||
mScreenHeight = getResources().getDisplayMetrics().heightPixels;
|
||||
}
|
||||
}
|
||||
|
||||
boolean starDrap = false;
|
||||
float X1;
|
||||
float X2;
|
||||
float Y1;
|
||||
float Y2;
|
||||
// 记录视图初始位置
|
||||
private float originalX;
|
||||
private float originalY;
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
if (starDrap) return true;
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
X1 = event.getRawX();
|
||||
Y1 = event.getRawY();
|
||||
// 记录视图当前位置
|
||||
originalX = getTranslationX();
|
||||
originalY = getTranslationY();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
X2 = event.getRawX();
|
||||
Y2 = event.getRawY();
|
||||
Action(X1, X2, Y1, Y2);
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
return starDrap;
|
||||
}
|
||||
|
||||
String TAG = "DropHourlView";
|
||||
|
||||
public boolean Action(float X1, float X2, float Y1, float Y2) {
|
||||
float ComparedX = X2 - X1;//第二次的X坐标的位置减去第一次X坐标的位置,代表X坐标上的变化情况
|
||||
float ComparedY = Y2 - Y1;//同理
|
||||
//当X坐标的变化量的绝对值大于Y坐标的变化量的绝对值,以X坐标的变化情况作为判断依据
|
||||
//上下左右的判断,都在一条直线上,但手指的操作不可能划直线,所有选择变化量大的方向上的量
|
||||
//作为判断依据
|
||||
if (Math.abs(ComparedX) > 30 || Math.abs(ComparedY) > 30) {
|
||||
Log.i(TAG, "Action: 拖动");
|
||||
starDrap = true;
|
||||
// setBackgroundResource(R.drawable.bg_home_drop_view);
|
||||
return true;
|
||||
} else {
|
||||
starDrap = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private float mOriginalRawX;
|
||||
private float mOriginalRawY;
|
||||
private float mOriginalX;
|
||||
private float mOriginalY;
|
||||
protected int mScreenWidth;
|
||||
private int mScreenHeight;
|
||||
private int mStatusBarHeight;
|
||||
|
||||
private void updateViewPosition(MotionEvent event) {
|
||||
// 计算新的Y位置
|
||||
float desY = mOriginalY + event.getRawY() - mOriginalRawY;
|
||||
|
||||
// 限制Y位置不超出屏幕边界
|
||||
if (desY < mStatusBarHeight) {
|
||||
desY = mStatusBarHeight;
|
||||
}
|
||||
if (desY > mScreenHeight - getHeight()) {
|
||||
desY = mScreenHeight - getHeight();
|
||||
}
|
||||
|
||||
// 计算新的X位置
|
||||
float desX = mOriginalX + event.getRawX() - mOriginalRawX;
|
||||
|
||||
// 限制X位置不超出屏幕边界
|
||||
if (desX < 0) {
|
||||
desX = 0;
|
||||
}
|
||||
if (desX > mScreenWidth - getWidth()) {
|
||||
desX = mScreenWidth - getWidth();
|
||||
}
|
||||
|
||||
// 设置视图的新位置
|
||||
setX(desX);
|
||||
setY(desY);
|
||||
}
|
||||
private void changeOriginalTouchParams(MotionEvent event) {
|
||||
mOriginalX = getX();//getX()相对于控件X坐标的距离
|
||||
mOriginalY = getY();
|
||||
mOriginalRawX = event.getRawX();//getRawX()指控件在屏幕上的X坐标
|
||||
mOriginalRawY = event.getRawY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (event == null) {
|
||||
return false;
|
||||
}
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
changeOriginalTouchParams(event);
|
||||
updateSize(); // 添加这行确保尺寸是最新的
|
||||
// ... 其他现有代码 ...
|
||||
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
|
||||
updateViewPosition(event); // 使用更新后的带边界检查的方法
|
||||
|
||||
// setBackgroundResource(R.drawable.bg_home_drop_view);
|
||||
// 使用屏幕绝对坐标计算新位置
|
||||
// float newX = originalX + (event.getRawX() - X1);
|
||||
// float newY = originalY + (event.getRawY() - Y1);
|
||||
//
|
||||
// // 限制X和Y坐标在屏幕范围内
|
||||
// newX = Math.max(0, Math.min(newX, screenWidth - getWidth()));
|
||||
// newY = Math.max(0, Math.min(newY, screenHeight - getHeight()));
|
||||
//
|
||||
// setTranslationX(newX);
|
||||
// setTranslationY(newY);
|
||||
// X2 = event.getRawX();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
starDrap = false;
|
||||
int sw = ScreenUtils.getScreenWidth();
|
||||
Log.i(TAG, "onTouchEvent: " + sw + "," + X2);
|
||||
boolean isR = getTranslationX() + getWidth() / 2 >= sw / 2;//贴边方向
|
||||
|
||||
// 获取当前Y坐标
|
||||
float currentY = getTranslationY();
|
||||
|
||||
// 创建X轴和Y轴的动画
|
||||
ObjectAnimator animX = ObjectAnimator.ofFloat(this, "translationX", isR ? sw - getWidth() : 0f).setDuration(200);
|
||||
// Y轴保持当前位置,但确保在屏幕范围内
|
||||
currentY = Math.max(0, Math.min(currentY, screenHeight - getHeight()));
|
||||
ObjectAnimator animY = ObjectAnimator.ofFloat(this, "translationY", currentY).setDuration(200);
|
||||
|
||||
animX.start();
|
||||
animY.start();
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void doRevealAnimation(View mPuppet, boolean flag) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
int[] vLocation = new int[2];
|
||||
getLocationInWindow(vLocation);
|
||||
int centerX = vLocation[0] + getMeasuredWidth() / 2;
|
||||
int centerY = vLocation[1] + getMeasuredHeight() / 2;
|
||||
|
||||
int height = ScreenUtils.getScreenHeight();
|
||||
int width = ScreenUtils.getScreenWidth();
|
||||
int maxRradius = (int) Math.hypot(height, width);
|
||||
Log.e("hei", maxRradius + "");
|
||||
|
||||
if (flag) {
|
||||
mPuppet.setVisibility(VISIBLE);
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, maxRradius, 0);
|
||||
animator.setDuration(600);
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
mPuppet.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
flag = false;
|
||||
} else {
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, 0, maxRradius);
|
||||
animator.setDuration(1000);
|
||||
animator.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mPuppet.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.xscm.moduleutil.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Shader;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
|
||||
/**
|
||||
* com.xscm.moduleutil.widget
|
||||
* qx 爵位中的文字渐变颜色
|
||||
* 2025/11/8
|
||||
*/
|
||||
public class GradientTextView extends AppCompatTextView {
|
||||
|
||||
public GradientTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public GradientTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public GradientTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (changed) {
|
||||
createGradient();
|
||||
}
|
||||
}
|
||||
|
||||
private void createGradient() {
|
||||
// 获取TextView的宽度
|
||||
int width = getWidth();
|
||||
if (width > 0) {
|
||||
// 创建从左到右的线性渐变 #A292FF -> #FFFFFF -> #A292FF
|
||||
LinearGradient gradient = new LinearGradient(
|
||||
0, 0, width, 0,
|
||||
new int[]{0xFFA292FF, 0xFFFFFFFF, 0xFFA292FF},
|
||||
new float[]{0f, 0.5f, 1f},
|
||||
Shader.TileMode.CLAMP
|
||||
);
|
||||
getPaint().setShader(gradient);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.xscm.moduleutil.widget;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class GrayscaleTransformation extends BitmapTransformation {
|
||||
private Float saturation;
|
||||
public GrayscaleTransformation(float saturation) {
|
||||
super();
|
||||
this.saturation = saturation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
|
||||
Bitmap result = pool.get(toTransform.getWidth(), toTransform.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
|
||||
Canvas canvas = new Canvas(result);
|
||||
ColorMatrix colorMatrix = new ColorMatrix();
|
||||
colorMatrix.setSaturation(saturation); // 设置为灰度
|
||||
Paint paint = new Paint();
|
||||
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
|
||||
canvas.drawBitmap(toTransform, 0, 0, paint);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
|
||||
messageDigest.update("grayscale transformation".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package com.xscm.moduleutil.widget
|
||||
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.LinearGradient
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Shader
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import com.xscm.moduleutil.R
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 流光字体
|
||||
* @author TXZ
|
||||
* @version 1.0
|
||||
* created by 2024/5/23 9:32
|
||||
*/
|
||||
class ShineTextView : AppCompatTextView {
|
||||
|
||||
//是否开启流光,默认开启
|
||||
var isShine = true
|
||||
|
||||
//默认是流光效果 0 流光 1 注入效果
|
||||
var shineType = 0
|
||||
//流光效果下字体流动次数
|
||||
var shineCount: Int = Int.MAX_VALUE
|
||||
//注入效果 开始,中间,结束
|
||||
var startColor: Int = Color.BLACK
|
||||
var shineColor: Int = Color.BLACK
|
||||
var endColor: Int = Color.BLACK
|
||||
//一次动效时长
|
||||
var shineDuration: Int = 1000
|
||||
|
||||
var _count: Int = 0 //自行运行动画次数
|
||||
|
||||
private lateinit var mLinearGradient: LinearGradient
|
||||
private var mGradientMatrix: Matrix = Matrix()
|
||||
private var mViewWidth = 0
|
||||
private var mTranslate = 0
|
||||
|
||||
constructor(context: Context) : this(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context, attrs, defStyleAttr
|
||||
) {
|
||||
obtainAttributes(attrs!!)
|
||||
}
|
||||
|
||||
|
||||
private fun obtainAttributes(attrs: AttributeSet) {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShineTextView)
|
||||
typedArray.apply {
|
||||
isShine = typedArray.getBoolean(R.styleable.ShineTextView_isShine, isShine)
|
||||
shineType = typedArray.getInt(R.styleable.ShineTextView_shineType, shineType)
|
||||
startColor = typedArray.getColor(R.styleable.ShineTextView_startColor, startColor)
|
||||
shineColor = typedArray.getColor(R.styleable.ShineTextView_midColor, shineColor)
|
||||
endColor = typedArray.getColor(R.styleable.ShineTextView_endColor, endColor)
|
||||
shineCount = typedArray.getInt(R.styleable.ShineTextView_shineCount, shineCount)
|
||||
shineDuration =
|
||||
typedArray.getInt(R.styleable.ShineTextView_shineDuration, shineDuration)
|
||||
}
|
||||
typedArray.recycle()
|
||||
}
|
||||
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
super.onSizeChanged(w, h, oldw, oldh)
|
||||
if (isShine) {
|
||||
mViewWidth = measuredWidth
|
||||
when (shineType) {
|
||||
0 -> {
|
||||
//流光效果
|
||||
mLinearGradient = LinearGradient(
|
||||
0f,
|
||||
0f,
|
||||
(mViewWidth / 1).toFloat(),
|
||||
0f,
|
||||
intArrayOf(currentTextColor, shineColor, currentTextColor),
|
||||
null,
|
||||
Shader.TileMode.CLAMP
|
||||
)
|
||||
}
|
||||
|
||||
1 -> {
|
||||
mLinearGradient = LinearGradient(
|
||||
0f,
|
||||
0f,
|
||||
(mViewWidth / 6).toFloat(),
|
||||
0f,
|
||||
intArrayOf(endColor, shineColor, startColor),
|
||||
null,
|
||||
Shader.TileMode.CLAMP
|
||||
)
|
||||
}
|
||||
}
|
||||
paint.shader = mLinearGradient
|
||||
}else {
|
||||
mLinearGradient = LinearGradient(
|
||||
0f,
|
||||
0f,
|
||||
0f,
|
||||
0f,
|
||||
intArrayOf(Color.BLACK,Color.BLACK),
|
||||
null,
|
||||
Shader.TileMode.CLAMP
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
if (!isShine) return
|
||||
mTranslate += mViewWidth / (shineDuration / 50)
|
||||
if (mTranslate > 1.2 * mViewWidth) {
|
||||
mTranslate = -mViewWidth / 5
|
||||
_count++
|
||||
}
|
||||
mGradientMatrix.setTranslate(mTranslate.toFloat(), 0f)
|
||||
mLinearGradient.setLocalMatrix(mGradientMatrix)
|
||||
when {
|
||||
shineType == 0 && _count < shineCount -> postInvalidateDelayed(50)
|
||||
shineType == 1 && _count < 1 -> postInvalidateDelayed(50)
|
||||
else -> {
|
||||
mGradientMatrix.setTranslate((1.2 * mViewWidth).toFloat(), 0f)
|
||||
mLinearGradient.setLocalMatrix(mGradientMatrix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shareInterpolator="false">
|
||||
<translate
|
||||
android:duration="2000"
|
||||
android:fromYDelta="0"
|
||||
android:toYDelta="-20"
|
||||
android:repeatCount="infinite"
|
||||
android:repeatMode="reverse"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator" />
|
||||
</set>
|
||||
|
Before Width: | Height: | Size: 705 B |
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape android:shape="rectangle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:startColor="#fff7d1ff"
|
||||
android:endColor="#ffe477ff"
|
||||
android:angle="0"/>
|
||||
<corners
|
||||
android:topLeftRadius="10dp"
|
||||
android:topRightRadius="10dp"
|
||||
android:bottomLeftRadius="10dp"
|
||||
android:bottomRightRadius="10dp"/>
|
||||
</shape>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape android:shape="rectangle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
|
||||
android:startColor="#FFF1C2"
|
||||
android:endColor="#FFd762"
|
||||
android:angle="0"
|
||||
/>
|
||||
<corners
|
||||
android:topLeftRadius="10dp"
|
||||
android:topRightRadius="10dp"
|
||||
android:bottomLeftRadius="10dp"
|
||||
android:bottomRightRadius="10dp"/>
|
||||
</shape>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="180"
|
||||
android:startColor="#C5FFC9"
|
||||
android:centerColor="#F9E9FF"
|
||||
android:endColor="#C7ECFA"
|
||||
android:type="linear"
|
||||
android:useLevel="true" />
|
||||
<corners
|
||||
android:bottomLeftRadius="12dp"
|
||||
android:bottomRightRadius="12dp"
|
||||
android:topLeftRadius="12dp"
|
||||
android:topRightRadius="12dp" />
|
||||
</shape>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="180"
|
||||
android:centerColor="#fff9e9ff"
|
||||
android:endColor="#ffc7d3fa"
|
||||
android:startColor="#fffffac5"
|
||||
android:type="linear"
|
||||
android:useLevel="true" />
|
||||
<corners
|
||||
android:bottomLeftRadius="12dp"
|
||||
android:bottomRightRadius="12dp"
|
||||
android:topLeftRadius="12dp"
|
||||
android:topRightRadius="12dp" />
|
||||
</shape>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#ff1b1926" />
|
||||
<corners
|
||||
android:bottomLeftRadius="0dp"
|
||||
android:bottomRightRadius="0dp"
|
||||
android:topLeftRadius="14dp"
|
||||
android:topRightRadius="14dp" />
|
||||
</shape>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#2B2935"/>
|
||||
<corners android:radius="@dimen/dp_16"/>
|
||||
|
||||
</shape>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#3ABC6D"/>
|
||||
<corners android:radius="@dimen/dp_16"/>
|
||||
|
||||
</shape>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape android:shape="rectangle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#3ABC6D" />
|
||||
<corners android:radius="@dimen/dp_34"/>
|
||||
</shape>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="@dimen/dp_48" />
|
||||
<solid android:color="#FF8ACC" />
|
||||
</shape>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape android:shape="rectangle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#2A2925" />
|
||||
<corners android:radius="@dimen/dp_4"/>
|
||||
</shape>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="90"
|
||||
android:startColor="#FFDAED"
|
||||
android:centerColor="#ffd9ffe1"
|
||||
android:endColor="#F3FF98"
|
||||
android:type="linear"
|
||||
android:useLevel="true" />
|
||||
<corners
|
||||
android:bottomLeftRadius="4dp"
|
||||
android:bottomRightRadius="4dp"
|
||||
android:topLeftRadius="4dp"
|
||||
android:topRightRadius="4dp" />
|
||||
</shape>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#73040404" />
|
||||
<corners
|
||||
android:bottomLeftRadius="53dp"
|
||||
android:bottomRightRadius="53dp"
|
||||
android:topLeftRadius="53dp"
|
||||
android:topRightRadius="53dp" />
|
||||
</shape>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape android:shape="rectangle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#4d2a2a4e" />
|
||||
<corners android:topLeftRadius="6dp" android:topRightRadius="6dp" android:bottomLeftRadius="6dp" android:bottomRightRadius="6dp" />
|
||||
</shape>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="180"
|
||||
android:startColor="#C2EBFF"
|
||||
android:centerColor="#fff5d2f2"
|
||||
android:endColor="#FFF6F0"
|
||||
android:type="linear"
|
||||
android:useLevel="true" />
|
||||
<corners
|
||||
android:bottomLeftRadius="6dp"
|
||||
android:bottomRightRadius="6dp"
|
||||
android:topLeftRadius="6dp"
|
||||
android:topRightRadius="6dp" />
|
||||
</shape>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#262431" />
|
||||
<corners
|
||||
android:bottomLeftRadius="0dp"
|
||||
android:bottomRightRadius="0dp"
|
||||
android:topLeftRadius="14dp"
|
||||
android:topRightRadius="14dp" />
|
||||
</shape>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape android:shape="rectangle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:useLevel="true"
|
||||
android:startColor="#F8F6C7"
|
||||
android:endColor="#ffffffff"
|
||||
android:angle="0"/>
|
||||
<corners
|
||||
android:topLeftRadius="8dp"
|
||||
android:topRightRadius="8dp"
|
||||
android:bottomLeftRadius="8dp"
|
||||
android:bottomRightRadius="8dp"/>
|
||||
</shape>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape android:shape="rectangle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#AEEDFF"/>
|
||||
<corners
|
||||
android:topLeftRadius="8dp"
|
||||
android:topRightRadius="8dp"
|
||||
android:bottomLeftRadius="0dp"
|
||||
android:bottomRightRadius="0dp"/>
|
||||
</shape>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 用item标签限制整体尺寸:maxWidth=100dp,height=10dp(与tabIndicatorHeight一致) -->
|
||||
<item
|
||||
android:height="@dimen/dp_25"
|
||||
android:gravity="center"
|
||||
android:maxWidth="@dimen/dp_20">
|
||||
<!-- 最大宽度(根据需求调整) -->
|
||||
<!-- 固定高度(与tabIndicatorHeight匹配) -->
|
||||
<!-- 图片在item内居中 -->
|
||||
<!-- 嵌套bitmap设置图片资源和缩放模式 -->
|
||||
<bitmap
|
||||
android:dither="true"
|
||||
android:scaleType="center"
|
||||
android:src="@mipmap/tab_dy" />
|
||||
<!-- 你的图片资源 -->
|
||||
<!-- 等比例缩放,确保图片在maxWidth和height内完整显示 -->
|
||||
<!-- 抗锯齿优化 -->
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<!-- 背景填充颜色,如果你不需要内部填充颜色,可以设置为透明 -->
|
||||
<solid android:color="@color/white" />
|
||||
|
||||
<!-- 边框设置 -->
|
||||
<stroke
|
||||
android:width="0.5dp"
|
||||
android:color="#9FF9DF" />
|
||||
|
||||
<!-- 圆角设置 -->
|
||||
<corners android:radius="99dp" /> <!-- 你可以根据需要调整圆角大小 -->
|
||||
|
||||
</shape>
|
||||
@@ -1,127 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/bubble"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ease_row_pubilc_user_bg"
|
||||
android:maxWidth="@dimen/dp_256"
|
||||
android:minWidth="@dimen/dp_256"
|
||||
android:padding="@dimen/dp_8">
|
||||
|
||||
<!-- 网络背景图片 -->
|
||||
<!-- <ImageView-->
|
||||
<!-- android:id="@+id/network_background"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="0dp"-->
|
||||
<!-- tools:src="@mipmap/a1img_9"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent"-->
|
||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="parent"/>-->
|
||||
|
||||
<!-- 用户头像 -->
|
||||
<com.xscm.moduleutil.utils.MeHeadView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="@dimen/dp_28"
|
||||
android:layout_height="@dimen/dp_28"
|
||||
android:layout_marginStart="@dimen/dp_8"
|
||||
android:layout_marginTop="@dimen/dp_3"
|
||||
android:layout_marginEnd="@dimen/dp_3"
|
||||
android:layout_marginBottom="@dimen/dp_3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:riv_oval="true" />
|
||||
|
||||
<!-- 用户名称 -->
|
||||
<com.xscm.moduleutil.widget.ShineTextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_2"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/sp_12"
|
||||
app:isShine="false"
|
||||
app:layout_constraintStart_toEndOf="@+id/avatar"
|
||||
app:layout_constraintTop_toTopOf="@+id/avatar"
|
||||
tools:text="饶利" />
|
||||
|
||||
<!-- 用户标签容器 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/line"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_2"
|
||||
android:layout_marginTop="@dimen/dp_5"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintStart_toEndOf="@+id/avatar"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_name" />
|
||||
|
||||
<!-- 消息内容 -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:gravity="left|center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/dp_3"
|
||||
android:paddingEnd="@dimen/dp_10"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/avatar"
|
||||
app:layout_constraintTop_toBottomOf="@+id/line">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lineHeight="@dimen/dp_20"
|
||||
android:lineSpacingExtra="@dimen/dp_2"
|
||||
android:paddingStart="@dimen/dp_8"
|
||||
android:paddingEnd="@dimen/dp_8"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/sp_14"
|
||||
tools:text="饶利: 潇洒亼◇生2.0:"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<com.xscm.moduleutil.widget.AdaptiveImageView
|
||||
android:id="@+id/im_emj"
|
||||
android:layout_width="@dimen/dp_40"
|
||||
android:layout_height="@dimen/dp_40"
|
||||
android:layout_marginStart="@dimen/dp_2"
|
||||
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"
|
||||
tools:src="@mipmap/ic_launcher"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!-- <ImageView-->
|
||||
<!-- android:id="@+id/im_emj"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="0dp"-->
|
||||
<!-- android:layout_marginStart="@dimen/dp_2"-->
|
||||
<!-- android:paddingStart="@dimen/dp_8"-->
|
||||
<!-- android:paddingEnd="@dimen/dp_8"-->
|
||||
<!-- tools:src="@mipmap/ic_launcher"-->
|
||||
<!-- android:maxHeight="@dimen/dp_50"-->
|
||||
<!-- android:maxWidth="@dimen/dp_50"-->
|
||||
<!-- android:minWidth="@dimen/dp_40"-->
|
||||
<!-- android:minHeight="@dimen/dp_40"-->
|
||||
<!-- android:scaleType="centerCrop"-->
|
||||
<!-- android:adjustViewBounds="true"-->
|
||||
<!-- android:visibility="gone"-->
|
||||
<!-- tools:visibility="visible"-->
|
||||
|
||||
<!-- app:layout_constraintWidth_default="wrap"-->
|
||||
<!-- app:layout_constraintHeight_default="wrap"-->
|
||||
<!-- app:layout_constraintWidth_min="@dimen/dp_40"-->
|
||||
<!-- app:layout_constraintHeight_min="@dimen/dp_40"-->
|
||||
<!-- app:layout_constraintWidth_max="@dimen/dp_50"-->
|
||||
<!-- app:layout_constraintHeight_max="@dimen/dp_50"-->
|
||||
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent"/>-->
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/im"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/dp_45"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/gift_background"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.xscm.moduleutil.widget.GifAvatarOvalView
|
||||
android:id="@+id/iv_avatar"
|
||||
android:layout_width="@dimen/dp_30"
|
||||
android:layout_height="@dimen/dp_30"
|
||||
android:layout_margin="@dimen/dp_4"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="@id/im"
|
||||
app:layout_constraintStart_toStartOf="@+id/im"
|
||||
app:layout_constraintTop_toTopOf="@+id/im"
|
||||
tools:src="@drawable/ic_launcher_background" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_sender"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_4"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="@dimen/sp_12"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toEndOf="@+id/iv_avatar"
|
||||
app:layout_constraintTop_toTopOf="@+id/iv_avatar"
|
||||
tools:text="1111111" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_gift"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#fff"
|
||||
android:textSize="@dimen/sp_10"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_sender"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_sender"
|
||||
tools:text="1111111" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_gift"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="@dimen/dp_10"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="@id/im"
|
||||
app:layout_constraintTop_toTopOf="@+id/tv_sender" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_count"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="40dp"
|
||||
android:fontFamily="@font/semibold"
|
||||
android:gravity="start|center_vertical"
|
||||
android:textColor="#FFF49F"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/im"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="X14" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_gravity="center"
|
||||
android:background="@drawable/shape_dialog">
|
||||
|
||||
<app.dinus.com.loadingdrawable.LoadingView
|
||||
android:id="@+id/cool_wait_view"
|
||||
android:layout_width="@dimen/dp_100"
|
||||
android:layout_height="@dimen/dp_100"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:loading_renderer="CoolWaitLoadingRenderer" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_loading_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_10"
|
||||
android:text="加载中..."
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:paddingBottom="@dimen/dp_10"
|
||||
android:layout_marginHorizontal="@dimen/dp_50"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cool_wait_view" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
|
||||
<com.tencent.qgame.animplayer.AnimView
|
||||
android:id="@+id/anim_cp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.58" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_head"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/guideline">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.xscm.moduleutil.widget.CircularImage
|
||||
android:id="@+id/room_cp_head1"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@mipmap/ic_launcher_app"
|
||||
app:riv_oval="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/room_cp_name1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:enabled="true"
|
||||
android:maxEms="5"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/color_999999"
|
||||
android:textSize="8sp"
|
||||
tools:text="" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="@dimen/dp_40"
|
||||
android:layout_height="0dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.xscm.moduleutil.widget.CircularImage
|
||||
android:id="@+id/room_cp_head2"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@mipmap/ic_launcher_app"
|
||||
app:riv_oval="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/room_cp_name2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:enabled="true"
|
||||
android:maxEms="5"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/color_999999"
|
||||
android:textSize="8sp"
|
||||
tools:text="" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
@@ -1,293 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
<!--说话动态图-->
|
||||
<com.xscm.moduleutil.widget.GifAvatarOvalView
|
||||
android:id="@+id/riv"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
android:layout_marginStart="@dimen/dp_12"
|
||||
android:layout_marginTop="@dimen/dp_12"
|
||||
android:layout_marginEnd="@dimen/dp_12"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@mipmap/room_ic_wheat_default"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.opensource.svgaplayer.SVGAImageView
|
||||
android:id="@+id/iv_ripple"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/dp_8"
|
||||
app:autoPlay="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1.05"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:loopCount="0"
|
||||
app:source="mic.svga" />
|
||||
|
||||
<!-- <com.xscm.moduleutil.widget.AvatarFrameView-->
|
||||
<!-- android:id="@+id/iv_ripple"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="0dp"-->
|
||||
<!-- android:layout_marginTop="@dimen/dp_8"-->
|
||||
<!-- app:autoPlay="false"-->
|
||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||
<!-- app:layout_constraintDimensionRatio="1:1.05"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent"-->
|
||||
<!-- />-->
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_sex"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@mipmap/common_ic_headportriat_base"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toTopOf="@id/riv"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/view2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toTopOf="@id/riv" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tag_boos"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="14dp"
|
||||
android:src="@mipmap/room_ic_wheat_tag_boss"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/view2"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tag_type"
|
||||
android:layout_width="@dimen/dp_30"
|
||||
android:layout_height="@dimen/dp_20"
|
||||
android:layout_marginTop="@dimen/dp_5"
|
||||
android:src="@mipmap/zc"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv" />
|
||||
|
||||
<!-- <TextView-->
|
||||
<!-- android:id="@+id/tv_time"-->
|
||||
<!-- android:layout_width="@dimen/dp_35"-->
|
||||
<!-- android:layout_height="17.5dp"-->
|
||||
<!-- android:background="@drawable/room_bg_wheat_time"-->
|
||||
<!-- android:gravity="center"-->
|
||||
<!-- android:text="00:00"-->
|
||||
<!-- android:textColor="@color/white"-->
|
||||
<!-- android:textSize="@dimen/sp_9"-->
|
||||
<!-- android:visibility="gone"-->
|
||||
<!-- android:layout_marginBottom="@dimen/dp_6"-->
|
||||
<!-- app:layout_constraintBottom_toBottomOf="@id/riv"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="@id/riv"-->
|
||||
<!-- app:layout_constraintStart_toStartOf="@id/riv"-->
|
||||
<!-- tools:visibility="visible" />-->
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_time"
|
||||
android:layout_width="@dimen/dp_35"
|
||||
android:layout_height="17.5dp"
|
||||
android:background="@mipmap/za_s"
|
||||
android:gravity="center"
|
||||
android:text="00:00"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/sp_9"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
<com.xscm.moduleutil.widget.AvatarFrameView
|
||||
android:id="@+id/iv_frame"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="@dimen/dp_12"
|
||||
android:layout_marginTop="@dimen/dp_12"
|
||||
android:layout_marginEnd="@dimen/dp_12"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/view_riv_bottom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="7dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/cl_guide1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.2" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="@dimen/dp_5"
|
||||
android:paddingRight="@dimen/dp_5"
|
||||
android:singleLine="true"
|
||||
android:layout_marginTop="@dimen/dp_3"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/sp_10"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/riv"
|
||||
tools:text="麦位1"
|
||||
tools:textColor="@color/color_FF333333" />
|
||||
|
||||
<com.xscm.moduleutil.widget.WheatCharmView
|
||||
android:id="@+id/charm_view"
|
||||
android:layout_width="@dimen/dp_52"
|
||||
android:layout_height="@dimen/dp_12"
|
||||
android:layout_marginBottom="@dimen/dp_5"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_time_pk"
|
||||
android:layout_width="@dimen/dp_35"
|
||||
android:layout_height="17.5dp"
|
||||
android:background="@mipmap/za_s"
|
||||
android:layout_marginBottom="@dimen/dp_5"
|
||||
android:gravity="center"
|
||||
android:text="00:00"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/sp_9"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_name"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_shutup"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:src="@mipmap/room_ic_wheat_shutup"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintHeight_percent="0.05"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintWidth_percent="0.05"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_online"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"
|
||||
android:src="@mipmap/room_ic_owner_offline"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@+id/riv"
|
||||
app:layout_constraintStart_toStartOf="@+id/riv"
|
||||
app:layout_constraintTop_toTopOf="@+id/riv"/>
|
||||
|
||||
<com.xscm.moduleutil.widget.ExpressionImgView
|
||||
android:id="@+id/iv_face"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toTopOf="@id/riv"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_gift"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:0.6"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHeight_percent="0.7"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_maozi"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/dp_10"
|
||||
android:layout_marginTop="@dimen/dp_1"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@mipmap/ic_room_huangguan"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_frame"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_frame"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_no"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@mipmap/ic_room_xq_wno_male"
|
||||
android:gravity="center"
|
||||
android:text="1"
|
||||
android:textColor="#fff"
|
||||
android:textSize="@dimen/sp_10"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_frame"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</layout>
|
||||
@@ -1,274 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
<!--说话动态图-->
|
||||
<com.xscm.moduleutil.widget.CircularImage
|
||||
android:id="@+id/riv"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="@dimen/dp_12"
|
||||
android:layout_marginTop="@dimen/dp_12"
|
||||
android:layout_marginEnd="@dimen/dp_12"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@mipmap/room_ic_wheat_default"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<com.xscm.moduleutil.widget.AvatarFrameView
|
||||
android:id="@+id/iv_frame"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:layout_marginTop="@dimen/dp_10"
|
||||
app:layout_constraintHeight_percent="0.9"
|
||||
app:layout_constraintWidth_percent="0.8"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<com.opensource.svgaplayer.SVGAImageView
|
||||
android:id="@+id/iv_ripple"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/dp_8"
|
||||
app:autoPlay="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintHeight_percent="1"
|
||||
app:layout_constraintWidth_percent="1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:loopCount="0"
|
||||
app:source="mic.svga" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_sex"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@mipmap/common_ic_headportriat_base"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toTopOf="@id/riv"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/view2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toTopOf="@id/riv" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tag_boos"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="14dp"
|
||||
android:src="@mipmap/room_ic_wheat_tag_boss"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/view2"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tag_type"
|
||||
android:layout_width="@dimen/dp_30"
|
||||
android:layout_height="@dimen/dp_20"
|
||||
android:layout_marginTop="@dimen/dp_5"
|
||||
android:src="@mipmap/zc"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_time"
|
||||
android:layout_width="@dimen/dp_35"
|
||||
android:layout_height="17.5dp"
|
||||
android:background="@mipmap/za_s"
|
||||
android:gravity="center"
|
||||
android:text="00:00"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/sp_9"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
|
||||
|
||||
<View
|
||||
android:id="@+id/view_riv_bottom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="7dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/cl_guide1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.2" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="@dimen/dp_5"
|
||||
android:paddingRight="@dimen/dp_5"
|
||||
android:singleLine="true"
|
||||
android:layout_marginTop="@dimen/dp_6"
|
||||
android:textColor="@color/white"
|
||||
android:translationZ="@dimen/dp_10"
|
||||
android:textSize="@dimen/sp_10"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/riv"
|
||||
tools:text="麦位1"
|
||||
tools:textColor="@color/color_FF333333" />
|
||||
|
||||
<com.xscm.moduleutil.widget.WheatCharmView
|
||||
android:id="@+id/charm_view"
|
||||
android:layout_width="@dimen/dp_52"
|
||||
android:layout_height="@dimen/dp_12"
|
||||
android:layout_marginBottom="@dimen/dp_5"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_time_pk"
|
||||
android:layout_width="@dimen/dp_35"
|
||||
android:layout_height="17.5dp"
|
||||
android:background="@mipmap/za_s"
|
||||
android:layout_marginBottom="@dimen/dp_5"
|
||||
android:gravity="center"
|
||||
android:text="00:00"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/sp_9"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_name"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_shutup"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:src="@mipmap/room_ic_wheat_shutup"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintHeight_percent="0.05"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintWidth_percent="0.05"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_online"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@mipmap/room_ic_owner_offline"
|
||||
android:visibility="gone"
|
||||
android:tint="@color/black"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHeight_percent="0.82"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginTop="@dimen/dp_10"
|
||||
app:loopCount="0"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.xscm.moduleutil.widget.ExpressionImgView
|
||||
android:id="@+id/iv_face"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/riv"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
app:layout_constraintTop_toTopOf="@id/riv"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_gift"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:0.6"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHeight_percent="0.7"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_maozi"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/dp_10"
|
||||
android:layout_marginTop="@dimen/dp_1"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@mipmap/ic_room_huangguan"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_frame"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_frame"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_no"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@mipmap/ic_room_xq_wno_male"
|
||||
android:gravity="center"
|
||||
android:text="1"
|
||||
android:textColor="#fff"
|
||||
android:textSize="@dimen/sp_10"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_frame"
|
||||
app:layout_constraintEnd_toEndOf="@id/riv"
|
||||
app:layout_constraintStart_toStartOf="@id/riv"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
|
Before Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 896 B |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 518 B |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 904 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 890 B |
|
Before Width: | Height: | Size: 304 B |
|
Before Width: | Height: | Size: 784 B |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 10 KiB |