diff --git a/application/.gitignore b/application/.gitignore index 5c915a53..9a60edc2 100644 --- a/application/.gitignore +++ b/application/.gitignore @@ -14,3 +14,6 @@ .cxx local.properties .idea/ +app/build/ +login/build/ +assembly/build/ \ No newline at end of file diff --git a/application/README.cn.md b/application/README.cn.md new file mode 100644 index 00000000..b036b36e --- /dev/null +++ b/application/README.cn.md @@ -0,0 +1,95 @@ +# RTCube + +[English](README.md) | 简体中文 + +## 概述 + +RTCube 是一款功能强大的 UI 组件库,它基于腾讯云 `AtomicXCore` SDK 构建。`AtomicXCore` 整合了腾讯云实时音视频(TRTC)、即时通信(IM)、音视频通话(TUICallEngine) 和房间管理(TUIRoomEngine) 的核心能力,提供了状态驱动的(State-driven)API 设计。 + +RTCube 在 `AtomicXCore` 提供的核心能力之上,为您提供了一套预制的用户界面(UI),使您无需关心复杂的后端逻辑和状态管理,即可快速为您的 Android 应用集成视频互动直播、语音聊天室、音视频通话等功能。 + +## 功能特性 + +RTCube 基于 `AtomicXCore` 提供了以下核心业务场景的完整 UI 实现: + + * **视频/语音直播 (Live Streaming):** + + * **直播列表管理:** 拉取直播列表。 + * **开播与观看:** 创建直播间、加入直播。 + * **麦位管理:** 支持麦位管理,观众上麦/下麦。 + * **主播连麦 (Co-hosting):** 支持主播与主播(跨房)连麦。 + * **主播 PK (Battle):** 支持主播间 PK 互动。 + * **互动功能:** + * **礼物:** 支持发送和接收礼物。 + * **点赞:** 支持直播间点赞。 + * **弹幕:** 支持发送和接收弹幕消息。 + + * **音视频通话 (Calling):** + + * **基础通话:** 支持 1v1 及多人音视频通话。 + * **通话管理:** 支持接听、拒绝、挂断。 + * **设备管理:** 支持通话中的摄像头和麦克风控制。 + * **通话记录:** 支持查询和删除通话记录。 + + * **多人会议 (Room):** + + * **快速会议:** 支持一键创建/加入多人会议。 + * **邀请入会:** 支持邀请成员加入当前会议。 + * **会中管控:** 支持主持人对成员的音视频、麦位、成员列表进行管理。 + * **共享屏幕:** 支持会中屏幕共享。 + +## 快速开始 + +### 1. 环境准备 + + * Android Studio Giraffe (2022.3.1) 或更高版本 + * JDK 17 + * Android Gradle Plugin 8.x + * Android 7.0(API 24)或更高版本 + +### 2. 克隆仓库 + +```bash +git clone https://github.com/Tencent-RTC/TUIKit_Android.git +``` + +### 3. 打开工程 + +使用 Android Studio 打开 `TUIKit_Android/application` 目录,等待 Gradle 同步完成。 `settings.gradle` 中接入了 `tuilivekit`、`tuicallkit-kt`、`tuiroomkit` 等必要的 AtomicXCore 组件模块。 + +### 4. 运行项目 + +打开 `application/app/src/main/kotlin/com/tencent/rtcube/v2/debug/GenerateTestUserSig.kt`,填入您自己的腾讯云 `SDKAPPID` 与 `SECRETKEY`,然后编译并运行 `app` 模块。 + +## 架构 + +`RTCube` 的架构设计遵循分层原则: + +1. **TUILiveKit / TUICallKit / TUIRoomKit (UI 层):** + + * 提供预制的、可复用的 UI 组件。 + * 负责视图(View)的展示和用户交互。 + * 订阅 `AtomicXCore` 中的 `Store` 来获取状态并更新 UI。 + * 调用 `AtomicXCore` 中的 `Store` 方法来响应用户操作。 + +2. **AtomicXCore (核心层):** + + * **Stores:** (如 `LiveListStore`, `CallListStore`, `ConversationListStore`) 负责管理业务逻辑和状态(State)。 + * **Core Views:** (如 `LiveCoreView`, `ParticipantView`) 提供了驱动视频渲染的无 UI 视图容器。 + * **Engine 封装:** 封装了底层的 `RTCRoomEngine`, `TUICallEngine` 和 `IMSDK`,提供统一的 API。 + +3. **Tencent Cloud SDK (引擎层):** + + * `RTCRoomEngine` & `TUICallEngine`: 提供底层的实时音视频能力。 + * `IMSDK`: 提供即时通讯能力。 + +## 文档 + +* [AtomicXCore 文档](https://tencent-rtc.github.io/TUIKit_Android/documentation/atomicxcore) +* [官方文档 - 快速集成指南](https://cloud.tencent.com/document/product/647/106536) + +## 许可证 + +本项目遵循 [MIT 许可证](https://www.google.com/search?q=LICENSE)。 + +----- diff --git a/application/README.md b/application/README.md new file mode 100644 index 00000000..f98d2aa9 --- /dev/null +++ b/application/README.md @@ -0,0 +1,95 @@ +# RTCube + +English | [简体中文](README.cn.md) + +## Overview + +RTCube is a powerful UI component library built on top of the Tencent Cloud `AtomicXCore` SDK. `AtomicXCore` consolidates the core capabilities of Tencent Cloud Real-Time Communication (TRTC), Instant Messaging (IM), Audio/Video Calling (TUICallEngine), and Room Management (TUIRoomEngine), offering a state-driven API design. + +On top of the core capabilities provided by `AtomicXCore`, RTCube delivers a set of ready-to-use user interfaces (UI), allowing you to quickly integrate interactive video live streaming, voice chat rooms, audio/video calling, and more into your Android application—without worrying about complex backend logic or state management. + +## Features + +Based on `AtomicXCore`, RTCube provides complete UI implementations for the following core business scenarios: + + * **Video/Voice Live Streaming:** + + * **Live List Management:** Fetch the list of live streams. + * **Go Live & Watch:** Create live rooms and join live streams. + * **Seat Management:** Manage seats; audience members can take or leave the mic. + * **Co-hosting:** Support cross-room co-hosting between hosts. + * **Host Battle (PK):** Support interactive PK between hosts. + * **Interactive Features:** + * **Gifts:** Send and receive gifts. + * **Likes:** Send likes in the live room. + * **Barrage (Danmaku):** Send and receive barrage messages. + + * **Audio/Video Calling:** + + * **Basic Calls:** Support 1v1 and multi-party audio/video calls. + * **Call Management:** Support answering, rejecting, and hanging up calls. + * **Device Management:** Control the camera and microphone during calls. + * **Call History:** Query and delete call records. + + * **Multi-party Meetings (Room):** + + * **Quick Meetings:** One-click creation and joining of multi-party meetings. + * **Invite to Meeting:** Invite members to join the current meeting. + * **In-meeting Controls:** Hosts can manage members' audio/video, seats, and member list. + * **Screen Sharing:** Support screen sharing during meetings. + +## Quick Start + +### 1. Prerequisites + + * Android Studio Giraffe (2022.3.1) or later + * JDK 17 + * Android Gradle Plugin 8.x + * Android 7.0 (API 24) or later + +### 2. Clone the Repository + +```bash +git clone https://github.com/Tencent-RTC/TUIKit_Android.git +``` + +### 3. Open the Project + +Open `TUIKit_Android/application` with Android Studio and let Gradle sync the dependencies. All required AtomicXCore component modules (`tuilivekit`, `tuicallkit-kt`, `tuiroomkit`, etc.) are wired in through the top-level `settings.gradle`. + +### 4. Configure & Run + +Open `application/app/src/main/kotlin/com/tencent/rtcube/v2/debug/GenerateTestUserSig.kt`, fill in your Tencent Cloud `SDKAPPID` and `SECRETKEY`, then run the `app` module. + +## Architecture + +The architecture of `RTCube` follows a layered design: + +1. **TUILiveKit / TUICallKit / TUIRoomKit (UI Layer):** + + * Provides prebuilt, reusable UI components. + * Handles view presentation and user interaction. + * Subscribes to `Store`s in `AtomicXCore` to retrieve state and update the UI. + * Calls `Store` methods in `AtomicXCore` to respond to user actions. + +2. **AtomicXCore (Core Layer):** + + * **Stores:** (e.g., `LiveListStore`, `CallListStore`, `ConversationListStore`) Manage business logic and state. + * **Core Views:** (e.g., `LiveCoreView`, `ParticipantView`) Provide UI-less view containers that drive video rendering. + * **Engine Wrappers:** Wrap the underlying `RTCRoomEngine`, `TUICallEngine`, and `IMSDK`, providing a unified API. + +3. **Tencent Cloud SDK (Engine Layer):** + + * `RTCRoomEngine` & `TUICallEngine`: Provide low-level real-time audio/video capabilities. + * `IMSDK`: Provides instant messaging capabilities. + +## Documentation + +* [AtomicXCore Documentation](https://tencent-rtc.github.io/TUIKit_Android/documentation/atomicxcore) +* [Official Documentation - Quick Integration Guide](https://cloud.tencent.com/document/product/647/106536) + +## License + +This project is licensed under the [MIT License](https://www.google.com/search?q=LICENSE). + +----- diff --git a/application/app/.gitignore b/application/app/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/application/app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/application/app/build.gradle b/application/app/build.gradle index 21e6a0ee..81787aa3 100644 --- a/application/app/build.gradle +++ b/application/app/build.gradle @@ -2,28 +2,90 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { - namespace 'com.tencent.uikit.app' + namespace 'com.tencent.rtcube.v2' compileSdk 34 defaultConfig { - applicationId "com.trtc.uikit.livekit.example" - minSdkVersion 21 - targetSdkVersion 34 - versionCode 1 - versionName "1.0" + applicationId 'com.tencent.trtc' + minSdk 24 + targetSdk 34 + versionCode = ((project.findProperty('RTCUBE_VERSION_CODE') ?: '2') as String).toInteger() + versionName = (project.findProperty('RTCUBE_VERSION_NAME') ?: '2.0.0').toString() + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + + ndk { + abiFilters 'arm64-v8a', 'armeabi-v7a' + } + + manifestPlaceholders = [ + // ioa party name, used for IOA integration; values injected from gradle.properties + ACCESS_PARTY_NAME: 'com_tencent_trtc', + // vivo / honor push identifier, used for TIMPush integration; values injected from gradle.properties + VIVO_APPKEY : (project.findProperty('RTCUBE_VIVO_APPKEY') ?: ''), + VIVO_APPID : (project.findProperty('RTCUBE_VIVO_APPID') ?: ''), + HONOR_APPID : (project.findProperty('RTCUBE_HONOR_APPID') ?: '') + ] + } + + signingConfigs { + release { + storeFile file("trtc.keystore") + storePassword "tencent.com" + keyAlias "tencent" + keyPassword "tencent.com" + } } buildTypes { release { + signingConfig signingConfigs.release minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } - packagingOptions { - exclude '/META-INF/{AL2.0,LGPL2.1}' - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/NOTICE.txt' + flavorDimensions "channel" + productFlavors { + xiaomi { + dimension "channel" + applicationId "com.tencent.trtc" + } + rtcube { + dimension "channel" + applicationId "com.tencent.trtc" + } + tencentrtc { + dimension "channel" + applicationId "com.tencent.rtc.app" + } + rtcubelab { + dimension "channel" + applicationId "com.tencent.trtc" + isDefault true + } + } + + sourceSets { + main { + res.srcDirs( + 'src/main/res', + 'src/main/res-main', + 'src/main/res-mine', + 'src/main/res-privacy', + 'src/main/res-overseas' + ) + } + } + + buildFeatures { + viewBinding true + dataBinding true + buildConfig true + compose true + } + + composeOptions { + kotlinCompilerExtensionVersion '1.5.8' } compileOptions { @@ -32,24 +94,57 @@ android { } kotlinOptions { - jvmTarget = JavaVersion.VERSION_17 + jvmTarget = '17' + } + + lint { + error 'RtlHardcoded' + error 'RtlCompat' + error 'RtlEnabled' } } dependencies { - api project(':tuicallkit-kt') - api project(':tuilivekit') - api project(':tuiroomkit') - api rootProject.getProperties().containsKey("common") ? rootProject.ext.common : "io.trtc.uikit:common:3.3.0.1194" - api project(':debug') - - implementation("androidx.core:core:1.13.0") - implementation("androidx.appcompat:appcompat:1.6.1") - implementation "androidx.navigation:navigation-fragment:2.1.0" - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'androidx.cardview:cardview:1.0.0' - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14' - - androidTestImplementation libs.androidx.junit - androidTestImplementation libs.androidx.espresso.core -} \ No newline at end of file + implementation project(':login') + implementation project(':assembly') + + implementation libs.androidx.core.ktx + implementation libs.androidx.appcompat + implementation libs.androidx.activity.ktx + implementation libs.androidx.fragment.ktx + implementation libs.androidx.constraintlayout + implementation libs.material + + implementation libs.lifecycle.runtime.ktx + + implementation libs.kotlinx.coroutines.android + + implementation libs.okhttp + implementation libs.okhttp.logging + implementation libs.retrofit + implementation libs.retrofit.serialization + implementation libs.retrofit.gson + + implementation libs.kotlinx.serialization.json + + implementation libs.coil + implementation libs.coil.compose + + implementation platform(libs.compose.bom) + implementation libs.compose.ui + implementation libs.compose.ui.tooling.preview + implementation libs.compose.material3 + implementation libs.compose.foundation + implementation libs.compose.runtime + implementation libs.activity.compose + implementation libs.lifecycle.viewmodel.compose + implementation libs.lifecycle.runtime.compose + implementation libs.navigation.compose + debugImplementation libs.compose.ui.tooling + implementation 'com.journeyapps:zxing-android-embedded:4.3.0' + + debugImplementation libs.leakcanary + + // TIMPush + implementation 'com.tencent.timpush:timpush:latest.release' +} diff --git a/application/app/proguard-rules.pro b/application/app/proguard-rules.pro index 481bb434..9240dc7e 100644 --- a/application/app/proguard-rules.pro +++ b/application/app/proguard-rules.pro @@ -18,4 +18,39 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile +-keep class com.tencent.** { *; } + +-dontwarn com.tencent.bugly.** +-keep public class com.tencent.bugly.**{*;} + +-keep public class * extends com.qq.taf.jce.JceStruct{*;} + +-keep public class com.qq.jce.*{ +public * ; +protected * ; +} + +-keepclasseswithmembernames class * { + native ; +} + +-keep public interface com.tencent.feedback.eup.jni.NativeExceptionHandler{ +*; +} +-keep public class com.tencent.feedback.eup.jni.NativeExceptionUpload{ +*; +} +-keep public class com.tencent.bugly.crashreport.crash.jni.NativeExceptionHandler { + *; +} + +-keep class com.tencent.could.huiyansdk.** {*;} +-keep class com.tencent.could.aicamare.** {*;} +-keep class com.tencent.could.component.** {*;} +-keep class com.tencent.youtu.** {*;} +-keep class com.tencent.turingcam.** {*;} +-keep class com.tencent.turingfd.** {*;} +-keep class com.tenpay.utils.**{*;} +-keep class com.tencent.turingface.** {*;} +-keep class trpc.engine.yishan_websocket.** {*;} \ No newline at end of file diff --git a/application/app/src/androidTest/java/com/tencent/uikit/app/ExampleInstrumentedTest.kt b/application/app/src/androidTest/java/com/tencent/uikit/app/ExampleInstrumentedTest.kt deleted file mode 100644 index f3fadbf2..00000000 --- a/application/app/src/androidTest/java/com/tencent/uikit/app/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.tencent.uikit.app - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.tencent.uikit.app", appContext.packageName) - } -} \ No newline at end of file diff --git a/application/app/src/main/AndroidManifest.xml b/application/app/src/main/AndroidManifest.xml index 140ae62f..d7de1774 100644 --- a/application/app/src/main/AndroidManifest.xml +++ b/application/app/src/main/AndroidManifest.xml @@ -2,25 +2,40 @@ + + + + + + + + + + - + tools:replace="android:allowBackup,android:theme,android:label" + android:theme="@style/Theme.RTCubeV2"> + + + + + android:theme="@style/Theme.RTCubeV2"> @@ -28,59 +43,15 @@ - - - - - - + android:theme="@style/Theme.RTCubeV2" /> + android:theme="@style/Theme.RTCubeV2" /> - - - - - - - - - - - - \ No newline at end of file + diff --git a/application/app/src/main/assets/timpush-configs.json b/application/app/src/main/assets/timpush-configs.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/application/app/src/main/assets/timpush-configs.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/utils/GlideEngine.kt b/application/app/src/main/java/com/tencent/uikit/app/common/utils/GlideEngine.kt deleted file mode 100644 index 93c2f523..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/utils/GlideEngine.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.tencent.uikit.app.common.utils - -import android.graphics.Bitmap -import android.widget.ImageView -import com.bumptech.glide.Glide -import com.bumptech.glide.load.engine.DiskCacheStrategy -import com.bumptech.glide.request.RequestOptions -import com.tencent.qcloud.tuicore.TUILogin -import com.tencent.qcloud.tuicore.TUIThemeManager -import com.tencent.uikit.app.R -import java.util.concurrent.ExecutionException - -object GlideEngine { - - fun clear(imageView: ImageView) { - Glide.with(TUILogin.getAppContext()).clear(imageView) - } - - fun loadUserIcon(imageView: ImageView, uri: Any?) { - loadUserIcon(imageView, uri, 0) - } - - fun loadUserIcon(imageView: ImageView, uri: Any?, radius: Int) { - Glide.with(TUILogin.getAppContext()) - .load(uri) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .placeholder(TUIThemeManager.getAttrResId(TUILogin.getAppContext(), R.drawable.app_default_user_icon_light)) - .apply(RequestOptions().centerCrop().error(TUIThemeManager.getAttrResId(TUILogin.getAppContext(), R.drawable.app_default_user_icon_light))) - .into(imageView) - } - - @Throws(InterruptedException::class, ExecutionException::class) - fun loadBitmap(imageUrl: Any?, targetImageSize: Int): Bitmap { - if (imageUrl == null) { - throw IllegalArgumentException("Image URL cannot be null") - } - return Glide.with(TUILogin.getAppContext()) - .asBitmap() - .load(imageUrl) - .apply(RequestOptions().error(TUIThemeManager.getAttrResId(TUILogin.getAppContext(), R.drawable.app_default_user_icon_light))) - .into(targetImageSize, targetImageSize) - .get() - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/utils/ImageUtil.kt b/application/app/src/main/java/com/tencent/uikit/app/common/utils/ImageUtil.kt deleted file mode 100644 index 92ecad90..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/utils/ImageUtil.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.tencent.uikit.app.common.utils - -import android.graphics.Bitmap -import com.tencent.qcloud.tuicore.TUILogin -import com.tencent.qcloud.tuicore.util.SPUtils -import java.io.File -import java.io.FileOutputStream -import java.io.IOException - -object ImageUtil { - const val SP_IMAGE = "_conversation_group_face" - - /** - * @param outFile - * @param bitmap - * @return - */ - fun storeBitmap(outFile: File, bitmap: Bitmap): File { - if (!outFile.exists() || outFile.isDirectory) { - outFile.parentFile?.mkdirs() - } - var fOut: FileOutputStream? = null - try { - outFile.deleteOnExit() - outFile.createNewFile() - fOut = FileOutputStream(outFile) - bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut) - fOut.flush() - } catch (e1: IOException) { - outFile.deleteOnExit() - } finally { - if (fOut != null) { - try { - fOut.close() - } catch (e: IOException) { - e.printStackTrace() - outFile.deleteOnExit() - } - } - } - return outFile - } - - fun setGroupConversationAvatar(conversationId: String, url: String) { - val spUtils = SPUtils.getInstance("${TUILogin.getSdkAppId()} $SP_IMAGE") - spUtils.put(conversationId, url) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/utils/LayoutUtil.kt b/application/app/src/main/java/com/tencent/uikit/app/common/utils/LayoutUtil.kt deleted file mode 100644 index bdbb73b4..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/utils/LayoutUtil.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.tencent.uikit.app.common.utils - -import android.content.Context -import android.content.res.Configuration -import android.view.View -import com.tencent.qcloud.tuicore.ServiceInitializer - -object LayoutUtil { - fun isRTL(): Boolean { - val context: Context = ServiceInitializer.getAppContext() - val configuration: Configuration = context.resources.configuration - val layoutDirection = configuration.layoutDirection - return layoutDirection == View.LAYOUT_DIRECTION_RTL - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/utils/SoftKeyBoardUtil.kt b/application/app/src/main/java/com/tencent/uikit/app/common/utils/SoftKeyBoardUtil.kt deleted file mode 100644 index ad3c10f2..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/utils/SoftKeyBoardUtil.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.tencent.uikit.app.common.utils - -import android.content.Context -import android.graphics.Rect -import android.os.IBinder -import android.util.DisplayMetrics -import android.view.View -import android.view.Window -import android.view.WindowManager -import android.view.inputmethod.InputMethodManager -import com.tencent.qcloud.tuicore.TUIConfig - -object SoftKeyBoardUtil { - fun hideKeyBoard(token: IBinder) { - val imm = TUIConfig.getAppContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? - imm?.hideSoftInputFromWindow(token, 0) - } - - fun hideKeyBoard(window: Window) { - val imm = TUIConfig.getAppContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? - if (imm != null) { - if (isSoftInputShown(window)) { - imm.toggleSoftInput(0, 0) - } - } - } - - fun showKeyBoard(window: Window) { - val imm = TUIConfig.getAppContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? - if (imm != null) { - if (!isSoftInputShown(window)) { - imm.toggleSoftInput(0, 0) - } - } - } - - private fun isSoftInputShown(window: Window): Boolean { - val decorView = window.decorView - val screenHeight = decorView.height - val rect = Rect() - decorView.getWindowVisibleDisplayFrame(rect) - return screenHeight - rect.bottom - getNavigateBarHeight(window.windowManager) >= 0 - } - - private fun getNavigateBarHeight(windowManager: WindowManager): Int { - val metrics = DisplayMetrics() - windowManager.defaultDisplay.getMetrics(metrics) - val usableHeight = metrics.heightPixels - windowManager.defaultDisplay.getRealMetrics(metrics) - val realHeight = metrics.heightPixels - return if (realHeight > usableHeight) { - realHeight - usableHeight - } else { - 0 - } - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/utils/ThreadUtils.kt b/application/app/src/main/java/com/tencent/uikit/app/common/utils/ThreadUtils.kt deleted file mode 100644 index f4bf94f5..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/utils/ThreadUtils.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.tencent.uikit.app.common.utils - -import android.os.Handler -import android.os.Looper -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - -object ThreadUtils { - private val handler = Handler(Looper.getMainLooper()) - private val executors: ExecutorService = Executors.newCachedThreadPool() - - fun execute(runnable: Runnable) { - executors.execute(runnable) - } - - fun postOnUiThread(runnable: Runnable): Boolean { - return handler.post(runnable) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/BaseLightActivity.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/BaseLightActivity.kt deleted file mode 100644 index f1712095..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/BaseLightActivity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.content.Context -import android.os.Build -import android.os.Bundle -import android.view.View -import android.view.WindowManager -import android.view.inputmethod.InputMethodManager -import androidx.appcompat.app.AppCompatActivity -import com.tencent.qcloud.tuicore.TUIThemeManager -import com.tencent.uikit.app.R - -open class BaseLightActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) - window.statusBarColor = resources.getColor( - TUIThemeManager.getAttrResId(this, com.tencent.qcloud.tuicore.R.attr.core_header_start_color) - ) - window.navigationBarColor = resources.getColor(R.color.app_color_navigation_bar) - var vis = window.decorView.systemUiVisibility - vis = vis or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - vis = vis or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR - window.decorView.systemUiVisibility = vis - } - } - - override fun finish() { - hideSoftInput() - super.finish() - } - - fun hideSoftInput() { - val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - val window = window - if (window != null) { - imm.hideSoftInputFromWindow(window.decorView.windowToken, 0) - } - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/ConfirmDialogFragment.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/ConfirmDialogFragment.kt deleted file mode 100644 index b949ccda..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/ConfirmDialogFragment.kt +++ /dev/null @@ -1,93 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.app.Dialog -import android.os.Bundle -import android.text.TextUtils -import android.view.View -import android.widget.Button -import android.widget.TextView -import androidx.fragment.app.DialogFragment -import com.tencent.uikit.app.R - -class ConfirmDialogFragment : DialogFragment() { - private var positiveClickListener: PositiveClickListener? = - null - private var negativeClickListener: NegativeClickListener? = - null - - private var messageText: String? = null - private var positiveText: String? = null - private var negativeText: String? = null - private var buttonNegative: Button? = null - private var buttonPositive: Button? = null - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val dialog = Dialog(requireContext(), R.style.TRTCLiveConfirmDialogFragment) - dialog.setContentView(R.layout.app_dialog_confirm) - buttonPositive = dialog.findViewById(R.id.btn_positive) as Button - buttonNegative = dialog.findViewById(R.id.btn_negative) as Button - dialog.setCancelable(false) - initTextMessage(dialog) - initButtonPositive() - initButtonNegative() - return dialog - } - - private fun initTextMessage(dialog: Dialog) { - val textMessage = dialog.findViewById(R.id.tv_message) as TextView - textMessage.setText(messageText) - } - - private fun initButtonPositive() { - if (positiveClickListener == null) { - buttonPositive?.visibility = View.GONE - return - } - if (!TextUtils.isEmpty(positiveText)) { - buttonPositive?.text = positiveText - } - buttonPositive?.visibility = View.VISIBLE - buttonPositive?.setOnClickListener { positiveClickListener?.onClick() } - } - - private fun initButtonNegative() { - if (negativeClickListener == null) { - buttonNegative?.visibility = View.GONE - return - } - if (!TextUtils.isEmpty(negativeText)) { - buttonNegative?.text = negativeText - } - buttonNegative?.visibility = View.VISIBLE - buttonNegative?.setOnClickListener { negativeClickListener?.onClick() } - } - - fun setMessage(message: String?) { - messageText = message - } - - fun setPositiveText(text: String?) { - positiveText = text - buttonPositive?.visibility = View.VISIBLE - } - - fun setNegativeText(text: String?) { - negativeText = text - } - - fun setPositiveClickListener(listener: PositiveClickListener?) { - this.positiveClickListener = listener - } - - fun setNegativeClickListener(listener: NegativeClickListener?) { - this.negativeClickListener = listener - } - - interface PositiveClickListener { - fun onClick() - } - - interface NegativeClickListener { - fun onClick() - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/ITitleBarLayout.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/ITitleBarLayout.kt deleted file mode 100644 index b7d7c31a..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/ITitleBarLayout.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.view.View -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView - -/** - * Conversation list window {@link ConversationLayout}、chat window {@link ChatLayout} have title bar, - * The title bar is designed as a three-part title on the left, middle and right. The left can be - * picture + text, the middle is text, and the right can also be picture + text. These areas return the - * standard Android View,These Views can be interactively processed according to business needs。 - */ -interface ITitleBarLayout { - /** - * Set the click event of the left header - * - * @param listener - */ - fun setOnLeftClickListener(listener: View.OnClickListener?) - - /** - * Set the click event of the right title - * - * @param listener - */ - fun setOnRightClickListener(listener: View.OnClickListener?) - - /** - * set Title - */ - fun setTitle(title: String?, position: Position?) - - /** - * Return to the left header area - * - * @return - */ - fun getLeftGroup(): LinearLayout - - /** - * Return to the right header area - * - * @return - */ - fun getRightGroup(): LinearLayout - - /** - * Returns the image for the left header - * - * @return - */ - fun getLeftIcon(): ImageView - - /** - * Set the image for the left header - * - * @param resId - */ - fun setLeftIcon(resId: Int) - - /** - * Returns the image with the right header - * - * @return - */ - fun getRightIcon(): ImageView - - /** - * Set the image for the title on the right - * - * @param resId - */ - fun setRightIcon(resId: Int) - - /** - * Returns the text of the left header - * - * @return - */ - fun getLeftTitle(): TextView - - /** - * Returns the text of the middle title - * - * @return - */ - fun getMiddleTitle(): TextView - - /** - * Returns the text of the title on the right - * - * @return - */ - fun getRightTitle(): TextView - - /** - * enumeration value of the header area - */ - enum class Position { - /** - * left title - */ - LEFT, - - /** - * middle title - */ - MIDDLE, - - /** - * right title - */ - RIGHT - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/ImageSelectActivity.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/ImageSelectActivity.kt deleted file mode 100644 index a80e5968..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/ImageSelectActivity.kt +++ /dev/null @@ -1,448 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.app.ProgressDialog -import android.content.Intent -import android.graphics.Rect -import android.os.Bundle -import android.text.TextUtils -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Button -import android.widget.ImageView -import android.widget.RelativeLayout -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.load.DataSource -import com.bumptech.glide.load.engine.GlideException -import com.bumptech.glide.request.RequestListener -import com.bumptech.glide.request.RequestOptions -import com.bumptech.glide.request.target.Target -import com.tencent.qcloud.tuicore.TUIThemeManager -import com.tencent.uikit.app.R -import io.trtc.tuikit.atomicx.widget.basicwidget.toast.AtomicToast -import com.tencent.uikit.app.common.utils.LayoutUtil -import com.tencent.uikit.app.common.widget.gatherimage.SynthesizedImageView -import com.trtc.tuikit.common.util.ScreenUtil -import java.io.File -import java.io.Serializable - -class ImageSelectActivity : BaseLightActivity() { - companion object { - private val TAG = ImageSelectActivity::class.java.simpleName - - const val CHAT_CONVERSATION_BACKGROUND_DEFAULT_URL = - "chat/conversation/background/default/url" - const val RESULT_CODE_ERROR = -1 - const val RESULT_CODE_SUCCESS = 0 - const val TITLE = "title" - const val SPAN_COUNT = "spanCount" - const val DATA = "data" - const val ITEM_HEIGHT = "itemHeight" - const val ITEM_WIDTH = "itemWidth" - const val SELECTED = "selected" - const val PLACEHOLDER = "placeholder" - const val NEED_DOWNLOAD_LOCAL = "needDownload" - } - - private var defaultSpacing: Int = 0 - private var data: List? = null - private var selected: ImageBean? = null - private var placeHolder: Int = 0 - private var columnNum: Int = 0 - private lateinit var imageGrid: RecyclerView - private lateinit var gridLayoutManager: GridLayoutManager - private lateinit var gridAdapter: ImageGridAdapter - private lateinit var titleBarLayout: TitleBarLayout - private var itemHeight: Int = 0 - private var itemWidth: Int = 0 - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - defaultSpacing = ScreenUtil.dip2px(12f) - setContentView(R.layout.app_activity_image_select_layout) - - val intent = intent - val title = intent.getStringExtra(TITLE) - titleBarLayout = findViewById(R.id.image_select_title) - titleBarLayout.setTitle(title, ITitleBarLayout.Position.MIDDLE) - titleBarLayout.setTitle( - getString(com.tencent.qcloud.tuicore.R.string.sure), - ITitleBarLayout.Position.RIGHT - ) - titleBarLayout.getRightIcon().visibility = View.GONE - titleBarLayout.getRightTitle().setTextColor(0xFF006EFF.toInt()) - titleBarLayout.setOnLeftClickListener { - setResult(RESULT_CODE_ERROR) - finish() - } - - val needDownload = intent.getBooleanExtra(NEED_DOWNLOAD_LOCAL, false) - titleBarLayout.setOnRightClickListener { - if (selected == null) { - return@setOnRightClickListener - } - if (needDownload) { - downloadUrl() - } else { - val resultIntent = Intent() - resultIntent.putExtra(DATA, selected as Serializable) - setResult(RESULT_CODE_SUCCESS, resultIntent) - finish() - } - } - - @Suppress("UNCHECKED_CAST") - data = intent.getSerializableExtra(DATA) as? List - selected = intent.getSerializableExtra(SELECTED) as? ImageBean - placeHolder = intent.getIntExtra(PLACEHOLDER, 0) - itemHeight = intent.getIntExtra(ITEM_HEIGHT, 0) - itemWidth = intent.getIntExtra(ITEM_WIDTH, 0) - columnNum = intent.getIntExtra(SPAN_COUNT, 2) - gridLayoutManager = GridLayoutManager(this, columnNum) - imageGrid = findViewById(R.id.image_select_grid) - imageGrid.addItemDecoration(GridDecoration(columnNum, defaultSpacing, defaultSpacing)) - imageGrid.layoutManager = gridLayoutManager - imageGrid.itemAnimator = null - gridAdapter = ImageGridAdapter() - gridAdapter.setPlaceHolder(placeHolder) - gridAdapter.setSelected(selected) - gridAdapter.setOnItemClickListener { obj -> - selected = obj - setSelectedStatus() - } - gridAdapter.setItemWidth(itemWidth) - gridAdapter.setItemHeight(itemHeight) - imageGrid.adapter = gridAdapter - gridAdapter.setData(data) - setSelectedStatus() - gridAdapter.notifyDataSetChanged() - } - - private fun downloadUrl() { - if (selected == null) { - return - } - - if (selected!!.isDefault()) { - selected!!.setLocalPath(CHAT_CONVERSATION_BACKGROUND_DEFAULT_URL) - setResult(selected!!) - AtomicToast.show( - this, - resources.getString(R.string.app_set_success), - AtomicToast.Style.SUCCESS - ) - finish() - return - } - - val url = selected!!.getImageUri() - if (TextUtils.isEmpty(url)) { - Log.d(TAG, "DownloadUrl is null") - return - } - - val dialog = ProgressDialog(this) - dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER) - dialog.setCancelable(false) - dialog.setCanceledOnTouchOutside(false) - dialog.setOnDismissListener { - finish() - } - dialog.setMessage(resources.getString(R.string.app_setting)) - dialog.show() - - val finalBean = selected!! - Glide.with(this) - .downloadOnly() - .load(url) - .listener(object : RequestListener { - override fun onLoadFailed( - e: GlideException?, - model: Any?, - target: Target?, - isFirstResource: Boolean - ): Boolean { - dialog.cancel() - Log.e(TAG, "DownloadUrl onLoadFailed e = $e") - AtomicToast.show(this@ImageSelectActivity, resources.getString(R.string.app_set_fail), AtomicToast.Style.ERROR) - return false - } - - override fun onResourceReady( - resource: File?, - model: Any?, - target: Target?, - dataSource: DataSource?, - isFirstResource: Boolean - ): Boolean { - dialog.cancel() - val path = resource?.absolutePath - Log.e(TAG, "DownloadUrl resource path = $path") - finalBean.setLocalPath(path) - setResult(finalBean) - AtomicToast.show( - this@ImageSelectActivity, - resources.getString(R.string.app_set_success), - AtomicToast.Style.SUCCESS - ) - return false - } - }) - .preload() - } - - private fun setResult(bean: ImageBean) { - val resultIntent = Intent() - resultIntent.putExtra(DATA, bean as Serializable) - setResult(RESULT_CODE_SUCCESS, resultIntent) - finish() - } - - private fun setSelectedStatus() { - if (selected != null && data != null && data!!.contains(selected)) { - titleBarLayout.getRightTitle().isEnabled = true - titleBarLayout.getRightTitle().setTextColor( - resources.getColor( - TUIThemeManager.getAttrResId( - this, - com.tencent.qcloud.tuicore.R.attr.core_primary_color - ) - ) - ) - } else { - titleBarLayout.getRightTitle().isEnabled = false - titleBarLayout.getRightTitle().setTextColor(0xFF666666.toInt()) - } - gridAdapter.setSelected(selected) - } - - class ImageGridAdapter : RecyclerView.Adapter() { - private var itemWidth: Int = 0 - private var itemHeight: Int = 0 - private var data: List? = null - private var selected: ImageBean? = null - private var placeHolder: Int = 0 - private var onItemClickListener: OnItemClickListener? = null - - fun setData(data: List?) { - this.data = data - } - - fun setSelected(selected: ImageBean?) { - if (data == null || data!!.isEmpty()) { - this.selected = selected - } else { - this.selected = selected - notifyDataSetChanged() - } - } - - fun setPlaceHolder(placeHolder: Int) { - this.placeHolder = placeHolder - } - - fun setItemHeight(itemHeight: Int) { - this.itemHeight = itemHeight - } - - fun setItemWidth(itemWidth: Int) { - this.itemWidth = itemWidth - } - - fun setOnItemClickListener(onItemClickListener: OnItemClickListener) { - this.onItemClickListener = onItemClickListener - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder { - val view = - LayoutInflater.from(parent.context) - .inflate(R.layout.app_select_image_item_layout, parent, false) - return ImageViewHolder(view) - } - - override fun onBindViewHolder(holder: ImageViewHolder, position: Int) { - val imageView = holder.imageView - setItemLayoutParams(holder) - val imageBean = data!![position] - if (selected != null && imageBean != null && TextUtils.equals( - selected!!.getThumbnailUri(), - imageBean.getThumbnailUri() - ) - ) { - holder.selectBorderLayout.visibility = View.VISIBLE - } else { - holder.selectBorderLayout.visibility = View.GONE - } - - if (imageBean.getGroupGridAvatar() != null) { - holder.defaultLayout.visibility = View.GONE - if (imageView is SynthesizedImageView) { - val synthesizedImageView = imageView - val imageId = imageBean.getImageId() - synthesizedImageView.setImageId(imageId ?: "") - synthesizedImageView.displayImage(imageBean.getGroupGridAvatar()) - .load(imageId ?: "") - } - } else if (imageBean.isDefault()) { - holder.defaultLayout.visibility = View.VISIBLE - imageView.setImageResource(android.R.color.transparent) - } else { - holder.defaultLayout.visibility = View.GONE - Glide.with(holder.itemView.context) - .asBitmap() - .load(imageBean.getThumbnailUri()) - .placeholder(placeHolder) - .apply(RequestOptions().error(placeHolder)) - .into(imageView) - } - - holder.itemView.setOnClickListener { - onItemClickListener?.onClick(imageBean) - } - } - - private fun setItemLayoutParams(holder: ImageViewHolder) { - if (itemHeight > 0 && itemWidth > 0) { - val itemViewLayoutParams = holder.itemView.layoutParams - itemViewLayoutParams.width = itemWidth - itemViewLayoutParams.height = itemHeight - holder.itemView.layoutParams = itemViewLayoutParams - - val params = holder.imageView.layoutParams - params.width = itemWidth - params.height = itemHeight - holder.imageView.layoutParams = params - - val borderLayoutParams = holder.selectBorderLayout.layoutParams - borderLayoutParams.width = itemWidth - borderLayoutParams.height = itemHeight - holder.selectBorderLayout.layoutParams = borderLayoutParams - - val borderParams = holder.selectedBorder.layoutParams - borderParams.width = itemWidth - borderParams.height = itemHeight - holder.selectedBorder.layoutParams = borderParams - } - } - - override fun getItemCount(): Int { - return if (data == null || data!!.isEmpty()) { - 0 - } else data!!.size - } - - class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.content_image) - val selectedBorder: ImageView = itemView.findViewById(R.id.select_border) - val selectBorderLayout: RelativeLayout = - itemView.findViewById(R.id.selected_border_area) - val defaultLayout: Button = itemView.findViewById(R.id.default_image_layout) - } - } - - /** - * add spacing - */ - class GridDecoration( - private val columnNum: Int, // span count - private val leftRightSpace: Int, // vertical spacing - private val topBottomSpace: Int // horizontal spacing - ) : RecyclerView.ItemDecoration() { - - override fun getItemOffsets( - outRect: Rect, - view: View, - parent: RecyclerView, - state: RecyclerView.State - ) { - val position = parent.getChildAdapterPosition(view) - val column = position % columnNum - - val left = column * leftRightSpace / columnNum - val right = leftRightSpace * (columnNum - 1 - column) / columnNum - if (LayoutUtil.isRTL()) { - outRect.left = right - outRect.right = left - } else { - outRect.left = left - outRect.right = right - } - // add top spacing - if (position >= columnNum) { - outRect.top = topBottomSpace - } - } - } - - fun interface OnItemClickListener { - fun onClick(obj: ImageBean) - } - - class ImageBean : Serializable { - private var thumbnailUri: String? = null // for display - internal var imageUri: String? = null // for download - private var localPath: String? = null // for local path - private var isDefault = false // for default display - private var groupGridAvatar: List? = null // for group grid avatar - private var imageId: String? = null - - constructor() - - constructor(thumbnailUri: String?, imageUri: String?, isDefault: Boolean) { - this.thumbnailUri = thumbnailUri - this.imageUri = imageUri - this.isDefault = isDefault - } - - fun getImageUri(): String? { - return imageUri - } - - fun getThumbnailUri(): String? { - return thumbnailUri - } - - fun setImageUri(imageUri: String?) { - this.imageUri = imageUri - } - - fun setThumbnailUri(thumbnailUri: String?) { - this.thumbnailUri = thumbnailUri - } - - fun getLocalPath(): String? { - return localPath - } - - fun setLocalPath(localPath: String?) { - this.localPath = localPath - } - - fun isDefault(): Boolean { - return isDefault - } - - fun setDefault(aDefault: Boolean) { - isDefault = aDefault - } - - fun getGroupGridAvatar(): List? { - return groupGridAvatar - } - - fun setGroupGridAvatar(groupGridAvatar: List?) { - this.groupGridAvatar = groupGridAvatar - } - - fun getImageId(): String? { - return imageId - } - - fun setImageId(imageId: String?) { - this.imageId = imageId - } - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/PopupInputCard.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/PopupInputCard.kt deleted file mode 100644 index e3c92a58..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/PopupInputCard.kt +++ /dev/null @@ -1,248 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.animation.ValueAnimator -import android.app.Activity -import android.graphics.drawable.ColorDrawable -import android.text.Editable -import android.text.InputFilter -import android.text.Spanned -import android.text.TextUtils -import android.text.TextWatcher -import android.view.LayoutInflater -import android.view.View -import android.view.Window -import android.view.WindowManager -import android.view.animation.LinearInterpolator -import android.widget.Button -import android.widget.EditText -import android.widget.PopupWindow -import android.widget.TextView -import com.tencent.uikit.app.R -import io.trtc.tuikit.atomicx.widget.basicwidget.toast.AtomicToast -import com.tencent.uikit.app.common.utils.SoftKeyBoardUtil -import java.util.regex.Pattern - -class PopupInputCard(private val activity: Activity) { - private var popupWindow: PopupWindow - private lateinit var titleTv: TextView - private lateinit var editText: EditText - private lateinit var descriptionTv: TextView - private lateinit var positiveBtn: Button - private lateinit var closeBtn: View - private var positiveOnClickListener: OnClickListener? = null - private var textExceedListener: OnTextExceedListener? = null - - private var minLimit = 0 - private var maxLimit = Int.MAX_VALUE - private var rule: String? = null - private var notMachRuleTip: String? = null - private val lengthFilter = ByteLengthFilter() - - init { - val popupView = LayoutInflater.from(activity).inflate(R.layout.app_layout_popup_card, null) - titleTv = popupView.findViewById(R.id.popup_card_title) - editText = popupView.findViewById(R.id.popup_card_edit) - descriptionTv = popupView.findViewById(R.id.popup_card_description) - positiveBtn = popupView.findViewById(R.id.popup_card_positive_btn) - closeBtn = popupView.findViewById(R.id.close_btn) - - popupWindow = object : PopupWindow(popupView, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT, true) { - override fun showAtLocation(anchor: View?, gravity: Int, x: Int, y: Int) { - if (!activity.isFinishing) { - val dialogWindow = activity.window - startAnimation(dialogWindow, true) - } - editText.requestFocus() - if (activity.window != null) { - SoftKeyBoardUtil.showKeyBoard(activity.window) - } - super.showAtLocation(anchor, gravity, x, y) - } - - override fun dismiss() { - if (!activity.isFinishing) { - val dialogWindow = activity.window - startAnimation(dialogWindow, false) - } - super.dismiss() - } - } - - popupWindow.setBackgroundDrawable(ColorDrawable()) - popupWindow.isTouchable = true - popupWindow.isOutsideTouchable = false - popupWindow.animationStyle = R.style.PopupInputCardAnim - popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NEEDED - popupWindow.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE - popupWindow.setOnDismissListener { - if (activity.window != null) { - SoftKeyBoardUtil.hideKeyBoard(activity.window) - } - } - - positiveBtn.setOnClickListener { - val result = editText.text.toString() - - if (result.length < minLimit || result.length > maxLimit) { - AtomicToast.show(activity, notMachRuleTip ?: "", AtomicToast.Style.ERROR) - return@setOnClickListener - } - - if (!TextUtils.isEmpty(rule) && !Pattern.matches(rule, result)) { - AtomicToast.show(activity, notMachRuleTip ?: "", AtomicToast.Style.ERROR) - return@setOnClickListener - } - - positiveOnClickListener?.onClick(editText.text.toString()) - popupWindow.dismiss() - } - - closeBtn.setOnClickListener { - popupWindow.dismiss() - } - - editText.filters = arrayOf(lengthFilter) - editText.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} - - override fun afterTextChanged(s: Editable?) { - if (!TextUtils.isEmpty(rule)) { - if (!Pattern.matches(rule, s.toString())) { - positiveBtn.isEnabled = false - } else { - positiveBtn.isEnabled = true - } - } - } - }) - } - - private fun startAnimation(window: Window, isShow: Boolean) { - val animator: ValueAnimator = if (isShow) { - ValueAnimator.ofFloat(1.0f, 0.5f) - } else { - ValueAnimator.ofFloat(0.5f, 1.0f) - } - animator.addUpdateListener { animation -> - val lp = window.attributes - lp.alpha = animation.animatedValue as Float - window.attributes = lp - } - val interpolator = LinearInterpolator() - animator.duration = 200 - animator.interpolator = interpolator - animator.start() - } - - fun show(rootView: View?, gravity: Int) { - popupWindow.showAtLocation(rootView, gravity, 0, 0) - } - - fun setTitle(title: String?) { - titleTv.text = title - } - - fun setDescription(description: String?) { - if (!TextUtils.isEmpty(description)) { - descriptionTv.visibility = View.VISIBLE - descriptionTv.text = description - } - } - - fun setContent(content: String?) { - editText.setText(content) - } - - fun setOnPositive(clickListener: OnClickListener?) { - positiveOnClickListener = clickListener - } - - fun setTextExceedListener(textExceedListener: OnTextExceedListener?) { - this.textExceedListener = textExceedListener - } - - fun setSingleLine(isSingleLine: Boolean) { - editText.isSingleLine = isSingleLine - } - - fun setMaxLimit(maxLimit: Int) { - this.maxLimit = maxLimit - lengthFilter.setLength(maxLimit) - } - - fun setMinLimit(minLimit: Int) { - this.minLimit = minLimit - } - - fun setRule(rule: String?) { - this.rule = if (TextUtils.isEmpty(rule)) { - "" - } else { - rule - } - } - - fun setNotMachRuleTip(notMachRuleTip: String?) { - this.notMachRuleTip = notMachRuleTip - } - - inner class ByteLengthFilter : InputFilter { - private var length = Int.MAX_VALUE - - fun setLength(length: Int) { - this.length = length - } - - override fun filter(source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence? { - var destLength = 0 - var destReplaceLength = 0 - var sourceLength = 0 - if (!TextUtils.isEmpty(dest)) { - destLength = dest.toString().toByteArray().size - destReplaceLength = dest!!.subSequence(dstart, dend).toString().toByteArray().size - } - if (!TextUtils.isEmpty(source)) { - sourceLength = source!!.subSequence(start, end).toString().toByteArray().size - } - val keepBytesLength = length - (destLength - destReplaceLength) - return if (keepBytesLength <= 0) { - textExceedListener?.onTextExceedMax() - "" - } else if (keepBytesLength >= sourceLength) { - null - } else { - textExceedListener?.onTextExceedMax() - getSource(source!!, start, keepBytesLength) - } - } - - private fun getSource(sequence: CharSequence, start: Int, keepLength: Int): CharSequence { - val sequenceLength = sequence.length - var end = 0 - for (i in 1..sequenceLength) { - if (sequence.subSequence(0, i).toString().toByteArray().size <= keepLength) { - end = i - } else { - break - } - } - if (end > 0 && Character.isHighSurrogate(sequence[end - 1])) { - --end - if (end == start) { - return "" - } - } - return sequence.subSequence(start, end) - } - } - - fun interface OnClickListener { - fun onClick(result: String) - } - - interface OnTextExceedListener { - fun onTextExceedMax() - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/RecycleFragmentNavigator.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/RecycleFragmentNavigator.kt deleted file mode 100644 index 83b131a1..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/RecycleFragmentNavigator.kt +++ /dev/null @@ -1,139 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.content.Context -import android.os.Bundle -import android.util.Log -import androidx.annotation.IdRes -import androidx.fragment.app.FragmentManager -import androidx.navigation.NavDestination -import androidx.navigation.NavOptions -import androidx.navigation.Navigator -import androidx.navigation.fragment.FragmentNavigator -import java.util.ArrayDeque - -/** - * Navigation 默认加载 fragment 的模式,每次会重新加载 view,导致每次导航切换的时候会重新加载view, - * 通过重写 FragmentNavigator 的 navigate 方法,将其中的 replace 方法 替换为 show 和 hide 方法 来完成 Fragment 的切换, - * 在应用切换导航的时候,会回收之前的view,避免每次重复加载fragment - */ -@Navigator.Name("RecycleFragmentNavigator") -class RecycleFragmentNavigator( - private val mContext: Context, - private val mManager: FragmentManager, - private val mContainerId: Int -) : FragmentNavigator( - mContext, - mManager, - mContainerId -) { - override fun navigate( - destination: FragmentNavigator.Destination, - args: Bundle?, - navOptions: NavOptions?, - navigatorExtras: Navigator.Extras? - ): NavDestination? { - if (mManager.isStateSaved) { - Log.i(TAG, "Ignoring navigate() call: FragmentManager has already" + " saved its state") - return null - } - var className = destination.getClassName() - if (className.get(0) == '.') { - className = mContext.getPackageName() + className - } - val ft = mManager.beginTransaction() - var enterAnim = navOptions?.enterAnim ?: -1 - var exitAnim = navOptions?.exitAnim ?: -1 - var popEnterAnim = navOptions?.popEnterAnim ?: -1 - var popExitAnim = navOptions?.popExitAnim ?: -1 - if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) { - enterAnim = if (enterAnim != -1) enterAnim else 0 - exitAnim = if (exitAnim != -1) exitAnim else 0 - popEnterAnim = if (popEnterAnim != -1) popEnterAnim else 0 - popExitAnim = if (popExitAnim != -1) popExitAnim else 0 - ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim) - } - - /** - * 1、先查询当前显示的fragment 不为空则将其hide - * 2、根据tag查询当前添加的fragment是否不为null,不为null则将其直接show - * 3、为null则通过instantiateFragment方法创建fragment实例 - * 4、将创建的实例添加在事务中 - */ - val fragment = mManager.primaryNavigationFragment //当前显示的fragment - if (fragment != null) { - ft.hide(fragment) - } - - val tag = destination.getId().toString() - var frag = mManager.findFragmentByTag(tag) - if (frag != null) { - ft.show(frag) - } else { - frag = instantiateFragment(mContext, mManager, className, args) - frag.setArguments(args) - ft.add(mContainerId, frag, tag) - } - ft.setPrimaryNavigationFragment(frag) - - @IdRes val destId = destination.getId() - - var mBackStack: ArrayDeque? = null - var isAdded = false - try { - val navigationClass = Class.forName("androidx.navigation.fragment.FragmentNavigator") - val field = navigationClass.getDeclaredField("mBackStack") - field.setAccessible(true) - mBackStack = field.get(this) as ArrayDeque? - val initialNavigation = mBackStack!!.isEmpty() - val isSingleTopReplacement = - (navOptions != null && !initialNavigation && navOptions.shouldLaunchSingleTop() - && mBackStack.peekLast() == destId) - - if (initialNavigation) { - isAdded = true - } else if (isSingleTopReplacement) { - if (mBackStack.size > 1) { - mManager.popBackStack( - generateBackStackName(mBackStack.size, mBackStack.peekLast()!!), - FragmentManager.POP_BACK_STACK_INCLUSIVE - ) - ft.addToBackStack(generateBackStackName(mBackStack.size, destId)) - } - } else { - ft.addToBackStack(generateBackStackName(mBackStack.size + 1, destId)) - } - if (navigatorExtras is Extras) { - val extras = navigatorExtras - for (sharedElement in extras.getSharedElements().entries) { - ft.addSharedElement(sharedElement.key, sharedElement.value) - } - } - ft.setReorderingAllowed(true) - ft.commit() - } catch (e: ClassNotFoundException) { - Log.e(TAG, "addToBackStack error, message is: " + e.message) - e.printStackTrace() - } catch (e: NoSuchFieldException) { - Log.e(TAG, "addToBackStack error, message is: " + e.message) - e.printStackTrace() - } catch (e: IllegalAccessException) { - Log.e(TAG, "addToBackStack error, message is: " + e.message) - e.printStackTrace() - } - - if (mBackStack != null && isAdded) { - mBackStack.add(destId) - return destination - } else { - return null - } - } - - private fun generateBackStackName(backIndex: Int, destId: Int): String { - return "$backIndex - $destId" - } - - companion object { - private const val TAG = "FixFragmentNavigator" - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/RoundCornerImageView.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/RoundCornerImageView.kt deleted file mode 100644 index 32b37ac5..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/RoundCornerImageView.kt +++ /dev/null @@ -1,121 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.content.Context -import android.content.res.TypedArray -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.PaintFlagsDrawFilter -import android.graphics.Path -import android.graphics.RectF -import android.util.AttributeSet -import android.view.View -import androidx.appcompat.widget.AppCompatImageView -import com.tencent.uikit.app.R - -class RoundCornerImageView : AppCompatImageView { - private val path = Path() - private val rectF = RectF() - private val aliasFilter = PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG) - private var radius: Int = 0 - private var leftTopRadius: Int = 0 - private var rightTopRadius: Int = 0 - private var rightBottomRadius: Int = 0 - private var leftBottomRadius: Int = 0 - - constructor(context: Context) : super(context) { - init(context, null) - } - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { - init(context, attrs) - } - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - - private fun init(context: Context, attrs: AttributeSet?) { - setLayerType(View.LAYER_TYPE_HARDWARE, null) - val defaultRadius = 0 - if (attrs != null) { - val array: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundCornerImageView) - radius = array.getDimensionPixelOffset(R.styleable.RoundCornerImageView_corner_radius, defaultRadius) - leftTopRadius = array.getDimensionPixelOffset(R.styleable.RoundCornerImageView_left_top_corner_radius, defaultRadius) - rightTopRadius = array.getDimensionPixelOffset(R.styleable.RoundCornerImageView_right_top_corner_radius, defaultRadius) - rightBottomRadius = array.getDimensionPixelOffset(R.styleable.RoundCornerImageView_right_bottom_corner_radius, defaultRadius) - leftBottomRadius = array.getDimensionPixelOffset(R.styleable.RoundCornerImageView_left_bottom_corner_radius, defaultRadius) - array.recycle() - } - - if (defaultRadius == leftTopRadius) { - leftTopRadius = radius - } - if (defaultRadius == rightTopRadius) { - rightTopRadius = radius - } - if (defaultRadius == rightBottomRadius) { - rightBottomRadius = radius - } - if (defaultRadius == leftBottomRadius) { - leftBottomRadius = radius - } - } - - fun setLeftBottomRadius(leftBottomRadius: Int) { - this.leftBottomRadius = leftBottomRadius - } - - fun setLeftTopRadius(leftTopRadius: Int) { - this.leftTopRadius = leftTopRadius - } - - fun setRadius(radius: Int) { - this.radius = radius - leftBottomRadius = radius - rightBottomRadius = radius - rightTopRadius = radius - leftTopRadius = radius - } - - fun setRightBottomRadius(rightBottomRadius: Int) { - this.rightBottomRadius = rightBottomRadius - } - - fun setRightTopRadius(rightTopRadius: Int) { - this.rightTopRadius = rightTopRadius - } - - fun getLeftBottomRadius(): Int { - return leftBottomRadius - } - - fun getLeftTopRadius(): Int { - return leftTopRadius - } - - fun getRadius(): Int { - return radius - } - - fun getRightBottomRadius(): Int { - return rightBottomRadius - } - - fun getRightTopRadius(): Int { - return rightTopRadius - } - - override fun onDraw(canvas: Canvas) { - path.reset() - canvas.drawFilter = aliasFilter - rectF.set(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat()) - // left-top -> right-top -> right-bottom -> left-bottom - val radius = floatArrayOf( - leftTopRadius.toFloat(), leftTopRadius.toFloat(), - rightTopRadius.toFloat(), rightTopRadius.toFloat(), - rightBottomRadius.toFloat(), rightBottomRadius.toFloat(), - leftBottomRadius.toFloat(), leftBottomRadius.toFloat() - ) - path.addRoundRect(rectF, radius, Path.Direction.CW) - canvas.clipPath(path) - super.onDraw(canvas) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/RoundFrameLayout.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/RoundFrameLayout.kt deleted file mode 100644 index 3c4cafb1..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/RoundFrameLayout.kt +++ /dev/null @@ -1,121 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.content.Context -import android.content.res.TypedArray -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.PaintFlagsDrawFilter -import android.graphics.Path -import android.graphics.RectF -import android.util.AttributeSet -import android.view.View -import android.widget.FrameLayout -import com.tencent.uikit.app.R - -class RoundFrameLayout : FrameLayout { - private val path = Path() - private val rectF = RectF() - private val aliasFilter = PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG) - private var radius: Int = 0 - private var leftTopRadius: Int = 0 - private var rightTopRadius: Int = 0 - private var rightBottomRadius: Int = 0 - private var leftBottomRadius: Int = 0 - - constructor(context: Context) : super(context) { - init(context, null) - } - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { - init(context, attrs) - } - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - - private fun init(context: Context, attrs: AttributeSet?) { - setLayerType(View.LAYER_TYPE_HARDWARE, null) - val defaultRadius = 0 - if (attrs != null) { - val array: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundFrameLayout) - radius = array.getDimensionPixelOffset(R.styleable.RoundFrameLayout_corner_radius, defaultRadius) - leftTopRadius = array.getDimensionPixelOffset(R.styleable.RoundFrameLayout_left_top_corner_radius, defaultRadius) - rightTopRadius = array.getDimensionPixelOffset(R.styleable.RoundFrameLayout_right_top_corner_radius, defaultRadius) - rightBottomRadius = array.getDimensionPixelOffset(R.styleable.RoundFrameLayout_right_bottom_corner_radius, defaultRadius) - leftBottomRadius = array.getDimensionPixelOffset(R.styleable.RoundFrameLayout_left_bottom_corner_radius, defaultRadius) - array.recycle() - } - - if (defaultRadius == leftTopRadius) { - leftTopRadius = radius - } - if (defaultRadius == rightTopRadius) { - rightTopRadius = radius - } - if (defaultRadius == rightBottomRadius) { - rightBottomRadius = radius - } - if (defaultRadius == leftBottomRadius) { - leftBottomRadius = radius - } - } - - fun setLeftBottomRadius(leftBottomRadius: Int) { - this.leftBottomRadius = leftBottomRadius - } - - fun setLeftTopRadius(leftTopRadius: Int) { - this.leftTopRadius = leftTopRadius - } - - fun setRadius(radius: Int) { - this.radius = radius - leftBottomRadius = radius - rightBottomRadius = radius - rightTopRadius = radius - leftTopRadius = radius - } - - fun setRightBottomRadius(rightBottomRadius: Int) { - this.rightBottomRadius = rightBottomRadius - } - - fun setRightTopRadius(rightTopRadius: Int) { - this.rightTopRadius = rightTopRadius - } - - fun getLeftBottomRadius(): Int { - return leftBottomRadius - } - - fun getLeftTopRadius(): Int { - return leftTopRadius - } - - fun getRadius(): Int { - return radius - } - - fun getRightBottomRadius(): Int { - return rightBottomRadius - } - - fun getRightTopRadius(): Int { - return rightTopRadius - } - - override fun dispatchDraw(canvas: Canvas) { - path.reset() - canvas.drawFilter = aliasFilter - rectF.set(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat()) - // left-top -> right-top -> right-bottom -> left-bottom - val radius = floatArrayOf( - leftTopRadius.toFloat(), leftTopRadius.toFloat(), - rightTopRadius.toFloat(), rightTopRadius.toFloat(), - rightBottomRadius.toFloat(), rightBottomRadius.toFloat(), - leftBottomRadius.toFloat(), leftBottomRadius.toFloat() - ) - path.addRoundRect(rectF, radius, Path.Direction.CW) - canvas.clipPath(path) - super.dispatchDraw(canvas) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/TitleBarLayout.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/TitleBarLayout.kt deleted file mode 100644 index 65cdc6b3..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/TitleBarLayout.kt +++ /dev/null @@ -1,155 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.app.Activity -import android.content.Context -import android.content.res.TypedArray -import android.graphics.drawable.Drawable -import android.text.TextUtils -import android.util.AttributeSet -import android.view.View -import android.view.ViewGroup -import android.view.inputmethod.InputMethodManager -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.RelativeLayout -import android.widget.TextView -import com.tencent.qcloud.tuicore.TUIThemeManager -import com.tencent.uikit.app.R -import com.trtc.tuikit.common.util.ScreenUtil - -class TitleBarLayout : LinearLayout, ITitleBarLayout { - private lateinit var mLeftGroup: LinearLayout - private lateinit var mRightGroup: LinearLayout - private lateinit var mLeftTitle: TextView - private lateinit var mCenterTitle: TextView - private lateinit var mRightTitle: TextView - private lateinit var mLeftIcon: ImageView - private lateinit var mRightIcon: ImageView - private lateinit var mTitleLayout: RelativeLayout - private lateinit var unreadCountTextView: UnreadCountTextView - - constructor(context: Context) : super(context) { - init(context, null) - } - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { - init(context, attrs) - } - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } - - private fun init(context: Context, attrs: AttributeSet?) { - var middleTitle: String? = null - var canReturn = false - if (attrs != null) { - val array: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.TitleBarLayout) - middleTitle = array.getString(R.styleable.TitleBarLayout_title_bar_middle_title) - canReturn = array.getBoolean(R.styleable.TitleBarLayout_title_bar_can_return, false) - array.recycle() - } - inflate(context, R.layout.app_layout_title_bar, this) - mTitleLayout = findViewById(R.id.page_title_layout) - mLeftGroup = findViewById(R.id.page_title_left_group) - mRightGroup = findViewById(R.id.page_title_right_group) - mLeftTitle = findViewById(R.id.page_title_left_text) - mRightTitle = findViewById(R.id.page_title_right_text) - mCenterTitle = findViewById(R.id.page_title) - mLeftIcon = findViewById(R.id.page_title_left_icon) - val leftIconDrawable: Drawable? = mLeftIcon.background - leftIconDrawable?.isAutoMirrored = true - mRightIcon = findViewById(R.id.page_title_right_icon) - unreadCountTextView = findViewById(R.id.new_message_total_unread) - - val params = mTitleLayout.layoutParams as LayoutParams - params.height = ScreenUtil.getPxByDp(50f) - mTitleLayout.layoutParams = params - setBackgroundResource(TUIThemeManager.getAttrResId(context, R.drawable.app_title_bar_bg_light)) - - val iconSize = ScreenUtil.dip2px(20f) - var iconParams = mLeftIcon.layoutParams - iconParams.width = iconSize - iconParams.height = iconSize - mLeftIcon.layoutParams = iconParams - iconParams = mRightIcon.layoutParams - iconParams.width = iconSize - iconParams.height = iconSize - - mRightIcon.layoutParams = iconParams - - if (canReturn) { - setLeftReturnListener(context) - } - if (!TextUtils.isEmpty(middleTitle)) { - mCenterTitle.text = middleTitle - } - } - - fun setLeftReturnListener(context: Context) { - mLeftGroup.setOnClickListener { - if (context is Activity) { - val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(this@TitleBarLayout.windowToken, 0) - context.finish() - } - } - } - - override fun setOnLeftClickListener(listener: OnClickListener?) { - mLeftGroup.setOnClickListener(listener) - } - - override fun setOnRightClickListener(listener: OnClickListener?) { - mRightGroup.setOnClickListener(listener) - } - - override fun setTitle(title: String?, position: ITitleBarLayout.Position?) { - when (position) { - ITitleBarLayout.Position.LEFT -> mLeftTitle.text = title - ITitleBarLayout.Position.RIGHT -> mRightTitle.text = title - ITitleBarLayout.Position.MIDDLE -> mCenterTitle.text = title - else -> {} - } - } - - override fun getLeftGroup(): LinearLayout { - return mLeftGroup - } - - override fun getRightGroup(): LinearLayout { - return mRightGroup - } - - override fun getLeftIcon(): ImageView { - return mLeftIcon - } - - override fun setLeftIcon(resId: Int) { - mLeftIcon.setBackgroundResource(resId) - } - - override fun getRightIcon(): ImageView { - return mRightIcon - } - - override fun setRightIcon(resId: Int) { - mRightIcon.setBackgroundResource(resId) - } - - override fun getLeftTitle(): TextView { - return mLeftTitle - } - - override fun getMiddleTitle(): TextView { - return mCenterTitle - } - - override fun getRightTitle(): TextView { - return mRightTitle - } - - fun getUnreadCountTextView(): UnreadCountTextView { - return unreadCountTextView - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/UnreadCountTextView.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/UnreadCountTextView.kt deleted file mode 100644 index a4e573ad..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/UnreadCountTextView.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.tencent.uikit.app.common.widget - -import android.content.Context -import android.content.res.TypedArray -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF -import android.util.AttributeSet -import android.util.DisplayMetrics -import android.util.TypedValue -import android.view.View -import androidx.appcompat.widget.AppCompatTextView -import com.tencent.uikit.app.R - -class UnreadCountTextView : AppCompatTextView { - private var mNormalSize: Int = 0 - private lateinit var mPaint: Paint - - constructor(context: Context) : super(context) { - init(context, null) - } - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { - init(context, attrs) - } - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } - - private fun init(context: Context, attrs: AttributeSet?) { - textDirection = View.TEXT_DIRECTION_LTR - mNormalSize = dp2px(18.4f) - val typedArray: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.UnreadCountTextView) - val paintColor = typedArray.getColor(R.styleable.UnreadCountTextView_paint_color, resources.getColor(R.color.app_color_read_dot_bg)) - typedArray.recycle() - - mPaint = Paint() - mPaint.color = paintColor - mPaint.isAntiAlias = true - } - - fun setPaintColor(color: Int) { - mPaint.color = color - } - - override fun onDraw(canvas: Canvas) { - when (text.length) { - 0 -> { - val l = (measuredWidth - dp2px(6f)) / 2 - val t = l - val r = measuredWidth - l - val b = r - canvas.drawOval(RectF(l.toFloat(), t.toFloat(), r.toFloat(), b.toFloat()), mPaint) - } - 1 -> { - canvas.drawOval(RectF(0f, 0f, mNormalSize.toFloat(), mNormalSize.toFloat()), mPaint) - } - else -> { - canvas.drawRoundRect( - RectF(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat()), - measuredHeight / 2f, - measuredHeight / 2f, - mPaint - ) - } - } - super.onDraw(canvas) - } - - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - var width = mNormalSize - val height = mNormalSize - if (text.length > 1) { - width = mNormalSize + dp2px((text.length - 1) * 10f) - } - setMeasuredDimension(width, height) - } - - private fun dp2px(dp: Float): Int { - val displayMetrics: DisplayMetrics = resources.displayMetrics - return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics).toInt() - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/MultiImageData.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/MultiImageData.kt deleted file mode 100644 index 1abfe9f9..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/MultiImageData.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.tencent.uikit.app.common.widget.gatherimage - -import android.graphics.Bitmap -import android.graphics.Color -import java.util.* - -/** - * Multiple image data - */ -class MultiImageData : Cloneable { - companion object { - const val maxSize = 9 - } - - var imageUrls: MutableList? = null - var defaultImageResId: Int = 0 - var bitmapMap: MutableMap? = null - var bgColor = Color.parseColor("#cfd3d8") - - var targetImageSize: Int = 0 - var maxWidth: Int = 0 - var maxHeight: Int = 0 - var rowCount: Int = 0 - var columnCount: Int = 0 - var gap = 6 - - constructor() - - constructor(defaultImageResId: Int) { - this.defaultImageResId = defaultImageResId - } - - constructor(imageUrls: MutableList?, defaultImageResId: Int) { - this.imageUrls = imageUrls - this.defaultImageResId = defaultImageResId - } - -// fun getDefaultImageResId(): Int { -// return defaultImageResId -// } -// -// fun setDefaultImageResId(defaultImageResId: Int) { -// this.defaultImageResId = defaultImageResId -// } - -// fun getImageUrls(): MutableList? { -// return imageUrls -// } -// -// fun setImageUrls(imageUrls: MutableList?) { -// this.imageUrls = imageUrls -// } - - fun putBitmap(bitmap: Bitmap, position: Int) { - if (bitmapMap != null) { - synchronized(bitmapMap!!) { - bitmapMap!![position] = bitmap - } - } else { - bitmapMap = HashMap() - synchronized(bitmapMap!!) { - bitmapMap!![position] = bitmap - } - } - } - - fun getBitmap(position: Int): Bitmap? { - if (bitmapMap != null) { - synchronized(bitmapMap!!) { - return bitmapMap!![position] - } - } - return null - } - - fun size(): Int { - return if (imageUrls != null) { - if (imageUrls!!.size > maxSize) maxSize else imageUrls!!.size - } else { - 0 - } - } - - @Throws(CloneNotSupportedException::class) - public override fun clone(): MultiImageData { - val multiImageData = super.clone() as MultiImageData - if (imageUrls != null) { - multiImageData.imageUrls = ArrayList(imageUrls!!.size) - multiImageData.imageUrls!!.addAll(imageUrls!!) - } - if (bitmapMap != null) { - multiImageData.bitmapMap = HashMap() - multiImageData.bitmapMap!!.putAll(bitmapMap!!) - } - return multiImageData - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/ShadeImageView.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/ShadeImageView.kt deleted file mode 100644 index d045f7e3..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/ShadeImageView.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.tencent.uikit.app.common.widget.gatherimage - -import android.annotation.SuppressLint -import android.content.Context -import android.content.res.TypedArray -import android.graphics.* -import android.util.AttributeSet -import android.util.SparseArray -import android.widget.ImageView -import com.tencent.uikit.app.R -import com.trtc.tuikit.common.util.ScreenUtil - -@SuppressLint("AppCompatCustomView") -open class ShadeImageView : ImageView { - companion object { - private val sRoundBitmapArray = SparseArray() - } - - private val mShadePaint = Paint() - private var mRoundBitmap: Bitmap? = null - private var radius: Int = 0 - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { - init(context, attrs) - } - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } - - private fun init(context: Context, attrs: AttributeSet?) { - radius = ScreenUtil.dp2px(4.0f, resources.displayMetrics).toInt() - val array: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundRectImageStyle) - radius = array.getDimensionPixelSize(R.styleable.RoundRectImageStyle_round_radius, radius) - array.recycle() - setLayerType(LAYER_TYPE_HARDWARE, null) - } - - override fun onDraw(canvas: Canvas) { - super.onDraw(canvas) - mShadePaint.color = Color.RED - mShadePaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN) - mRoundBitmap = sRoundBitmapArray[measuredWidth + radius] - if (mRoundBitmap == null) { - mRoundBitmap = getRoundBitmap() - sRoundBitmapArray.put(measuredWidth + radius, mRoundBitmap) - } - canvas.drawBitmap(mRoundBitmap!!, 0f, 0f, mShadePaint) - } - - /** - * Get rounded rectangle - * - * @return Bitmap - */ - private fun getRoundBitmap(): Bitmap { - val output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) - val canvas = Canvas(output) - val color = Color.parseColor("#cfd3d8") - val rect = Rect(0, 0, measuredWidth, measuredHeight) - val rectF = RectF(rect) - val paint = Paint() - paint.isAntiAlias = true - canvas.drawARGB(0, 0, 0, 0) - paint.color = color - canvas.drawRoundRect(rectF, radius.toFloat(), radius.toFloat(), paint) - return output - } - - fun getRadius(): Int { - return radius - } - - fun setRadius(radius: Int) { - this.radius = radius - invalidate() - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/SynthesizedImageView.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/SynthesizedImageView.kt deleted file mode 100644 index dc6e4113..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/SynthesizedImageView.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.tencent.uikit.app.common.widget.gatherimage - -import android.content.Context -import android.content.res.TypedArray -import android.graphics.Color -import android.util.AttributeSet -import com.tencent.uikit.app.R - -class SynthesizedImageView : ShadeImageView { - /** - * Group Chat Avatar Synthesizer - */ - private lateinit var teamHeadSynthesizer: TeamHeadSynthesizer - private var imageSize = 100 - private var synthesizedBg = Color.parseColor("#cfd3d8") - private var defaultImageResId = 0 - private var imageGap = 6 - - constructor(context: Context) : super(context) { - init(context) - } - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { - initAttrs(attrs) - init(context) - } - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - initAttrs(attrs) - init(context) - } - - private fun initAttrs(attributeSet: AttributeSet?) { - val ta: TypedArray? = context.obtainStyledAttributes(attributeSet, R.styleable.SynthesizedImageView) - if (ta != null) { - synthesizedBg = ta.getColor(R.styleable.SynthesizedImageView_synthesized_image_bg, synthesizedBg) - defaultImageResId = ta.getResourceId(R.styleable.SynthesizedImageView_synthesized_default_image, defaultImageResId) - imageSize = ta.getDimensionPixelSize(R.styleable.SynthesizedImageView_synthesized_image_size, imageSize) - imageGap = ta.getDimensionPixelSize(R.styleable.SynthesizedImageView_synthesized_image_gap, imageGap) - ta.recycle() - } - } - - private fun init(context: Context) { - teamHeadSynthesizer = TeamHeadSynthesizer(context, this) - teamHeadSynthesizer.setMaxWidthHeight(imageSize, imageSize) - teamHeadSynthesizer.setDefaultImage(defaultImageResId) - teamHeadSynthesizer.setBgColor(synthesizedBg) - teamHeadSynthesizer.setGap(imageGap) - } - - fun displayImage(imageUrls: List?): SynthesizedImageView { - teamHeadSynthesizer.getMultiImageData().imageUrls=(imageUrls?.toMutableList()) - return this - } - - fun defaultImage(defaultImage: Int): SynthesizedImageView { - teamHeadSynthesizer.setDefaultImage(defaultImage) - return this - } - - fun synthesizedWidthHeight(maxWidth: Int, maxHeight: Int): SynthesizedImageView { - teamHeadSynthesizer.setMaxWidthHeight(maxWidth, maxHeight) - return this - } - - fun setImageId(id: String) { - teamHeadSynthesizer.setImageId(id) - } - - fun load(imageId: String) { - teamHeadSynthesizer.load(imageId) - } - - fun clear() { - teamHeadSynthesizer.clearImage() - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/Synthesizer.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/Synthesizer.kt deleted file mode 100644 index c8dbbcfc..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/Synthesizer.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tencent.uikit.app.common.widget.gatherimage - -import android.graphics.Bitmap -import android.graphics.Canvas - -interface Synthesizer { - fun synthesizeImageList(imageData: MultiImageData): Bitmap - fun asyncLoadImageList(imageData: MultiImageData): Boolean - fun drawDrawable(canvas: Canvas, imageData: MultiImageData) -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/TeamHeadSynthesizer.kt b/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/TeamHeadSynthesizer.kt deleted file mode 100644 index bed97f56..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/common/widget/gatherimage/TeamHeadSynthesizer.kt +++ /dev/null @@ -1,470 +0,0 @@ -package com.tencent.uikit.app.common.widget.gatherimage - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.graphics.Canvas -import android.graphics.Rect -import android.text.TextUtils -import android.widget.ImageView -import com.tencent.qcloud.tuicore.TUIConfig -import com.tencent.uikit.app.R -import com.tencent.uikit.app.common.utils.ImageUtil -import com.tencent.uikit.app.common.utils.GlideEngine -import com.tencent.uikit.app.common.utils.ThreadUtils -import java.io.File -import java.util.* -import java.util.concurrent.ExecutionException - -class TeamHeadSynthesizer(private val mContext: Context, private val imageView: ImageView) : - Synthesizer { - private lateinit var multiImageData: MultiImageData - - // It is safe to set and get only in the main thread - private var currentImageId = "" - - private val callback = object : Callback { - override fun onCall(bitmap: Bitmap, targetID: String) { - if (!TextUtils.equals(getImageId(), targetID)) { - return - } - GlideEngine.loadUserIcon(imageView, bitmap) - } - } - - init { - init() - } - - private fun init() { - multiImageData = MultiImageData() - } - - fun setMaxWidthHeight(maxWidth: Int, maxHeight: Int) { - multiImageData.maxWidth = maxWidth - multiImageData.maxHeight = maxHeight - } - - fun getMultiImageData(): MultiImageData { - return multiImageData - } - - fun getDefaultImage(): Int { - return multiImageData.defaultImageResId - } - - fun setDefaultImage(defaultImageResId: Int) { - multiImageData.defaultImageResId = defaultImageResId - } - - fun setBgColor(bgColor: Int) { - multiImageData.bgColor = bgColor - } - - fun setGap(gap: Int) { - multiImageData.gap = gap - } - - /** - * Set Grid params - * - * @param imagesSize Number of pictures - * @return gridParam[0] Rows gridParam[1] columns - */ - protected fun calculateGridParam(imagesSize: Int): IntArray { - val gridParam = IntArray(2) - if (imagesSize < 3) { - gridParam[0] = 1 - gridParam[1] = imagesSize - } else if (imagesSize <= 4) { - gridParam[0] = 2 - gridParam[1] = 2 - } else { - gridParam[0] = imagesSize / 3 + if (imagesSize % 3 == 0) 0 else 1 - gridParam[1] = 3 - } - return gridParam - } - - override fun synthesizeImageList(imageData: MultiImageData): Bitmap { - val mergeBitmap = - Bitmap.createBitmap(imageData.maxWidth, imageData.maxHeight, Bitmap.Config.ARGB_8888) - val canvas = Canvas(mergeBitmap) - drawDrawable(canvas, imageData) - canvas.save() - canvas.restore() - return mergeBitmap - } - - override fun asyncLoadImageList(imageData: MultiImageData): Boolean { - val loadSuccess = true - val imageUrls = imageData.imageUrls - if (imageUrls != null) { - for (i in imageUrls.indices) { - val defaultIcon = - BitmapFactory.decodeResource( - mContext.resources, - R.drawable.app_default_user_icon_light - ) - try { - val bitmap = asyncLoadImage(imageUrls[i], imageData.targetImageSize) - imageData.putBitmap(bitmap, i) - } catch (e: InterruptedException) { - e.printStackTrace() - imageData.putBitmap(defaultIcon, i) - } catch (e: ExecutionException) { - e.printStackTrace() - imageData.putBitmap(defaultIcon, i) - } - } - } - return loadSuccess - } - - override fun drawDrawable(canvas: Canvas, imageData: MultiImageData) { - canvas.drawColor(imageData.bgColor) - val size = imageData.size() - val tCenter = (imageData.maxHeight + imageData.gap) / 2 - val bCenter = (imageData.maxHeight - imageData.gap) / 2 - val lCenter = (imageData.maxWidth + imageData.gap) / 2 - val rCenter = (imageData.maxWidth - imageData.gap) / 2 - val center = (imageData.maxHeight - imageData.targetImageSize) / 2 - - for (i in 0 until size) { - val rowNum = i / imageData.columnCount - val columnNum = i % imageData.columnCount - - val left = - (imageData.targetImageSize * (if (imageData.columnCount == 1) columnNum + 0.5 else columnNum.toDouble()) + imageData.gap * (columnNum + 1)).toInt() - val top = - (imageData.targetImageSize * (if (imageData.columnCount == 1) rowNum + 0.5 else rowNum.toDouble()) + imageData.gap * (rowNum + 1)).toInt() - val right = left + imageData.targetImageSize - val bottom = top + imageData.targetImageSize - - val bitmap = imageData.getBitmap(i) - when (size) { - 1 -> { - drawBitmapAtPosition(canvas, left, top, right, bottom, bitmap) - } - - 2 -> { - drawBitmapAtPosition( - canvas, - left, - center, - right, - center + imageData.targetImageSize, - bitmap - ) - } - - 3 -> { - if (i == 0) { - drawBitmapAtPosition( - canvas, - center, - top, - center + imageData.targetImageSize, - bottom, - bitmap - ) - } else { - drawBitmapAtPosition( - canvas, - imageData.gap * i + imageData.targetImageSize * (i - 1), - tCenter, - imageData.gap * i + imageData.targetImageSize * i, - tCenter + imageData.targetImageSize, - bitmap - ) - } - } - - 4 -> { - drawBitmapAtPosition(canvas, left, top, right, bottom, bitmap) - } - - 5 -> { - when (i) { - 0 -> { - drawBitmapAtPosition( - canvas, - rCenter - imageData.targetImageSize, - rCenter - imageData.targetImageSize, - rCenter, - rCenter, - bitmap - ) - } - - 1 -> { - drawBitmapAtPosition( - canvas, - lCenter, - rCenter - imageData.targetImageSize, - lCenter + imageData.targetImageSize, - rCenter, - bitmap - ) - } - - else -> { - drawBitmapAtPosition( - canvas, - imageData.gap * (i - 1) + imageData.targetImageSize * (i - 2), - tCenter, - imageData.gap * (i - 1) + imageData.targetImageSize * (i - 1), - tCenter + imageData.targetImageSize, - bitmap - ) - } - } - } - - 6 -> { - if (i < 3) { - drawBitmapAtPosition( - canvas, - imageData.gap * (i + 1) + imageData.targetImageSize * i, - bCenter - imageData.targetImageSize, - imageData.gap * (i + 1) + imageData.targetImageSize * (i + 1), - bCenter, - bitmap - ) - } else { - drawBitmapAtPosition( - canvas, - imageData.gap * (i - 2) + imageData.targetImageSize * (i - 3), - tCenter, - imageData.gap * (i - 2) + imageData.targetImageSize * (i - 2), - tCenter + imageData.targetImageSize, - bitmap - ) - } - } - - 7 -> { - when { - i == 0 -> { - drawBitmapAtPosition( - canvas, - center, - imageData.gap, - center + imageData.targetImageSize, - imageData.gap + imageData.targetImageSize, - bitmap - ) - } - - i in 1..3 -> { - drawBitmapAtPosition( - canvas, - imageData.gap * i + imageData.targetImageSize * (i - 1), - center, - imageData.gap * i + imageData.targetImageSize * i, - center + imageData.targetImageSize, - bitmap - ) - } - - else -> { - drawBitmapAtPosition( - canvas, - imageData.gap * (i - 3) + imageData.targetImageSize * (i - 4), - tCenter + imageData.targetImageSize / 2, - imageData.gap * (i - 3) + imageData.targetImageSize * (i - 3), - tCenter + imageData.targetImageSize / 2 + imageData.targetImageSize, - bitmap - ) - } - } - } - - 8 -> { - when { - i == 0 -> { - drawBitmapAtPosition( - canvas, - rCenter - imageData.targetImageSize, - imageData.gap, - rCenter, - imageData.gap + imageData.targetImageSize, - bitmap - ) - } - - i == 1 -> { - drawBitmapAtPosition( - canvas, - lCenter, - imageData.gap, - lCenter + imageData.targetImageSize, - imageData.gap + imageData.targetImageSize, - bitmap - ) - } - - i in 2..4 -> { - drawBitmapAtPosition( - canvas, - imageData.gap * (i - 1) + imageData.targetImageSize * (i - 2), - center, - imageData.gap * (i - 1) + imageData.targetImageSize * (i - 1), - center + imageData.targetImageSize, - bitmap - ) - } - - else -> { - drawBitmapAtPosition( - canvas, - imageData.gap * (i - 4) + imageData.targetImageSize * (i - 5), - tCenter + imageData.targetImageSize / 2, - imageData.gap * (i - 4) + imageData.targetImageSize * (i - 4), - tCenter + imageData.targetImageSize / 2 + imageData.targetImageSize, - bitmap - ) - } - } - } - - 9 -> { - drawBitmapAtPosition(canvas, left, top, right, bottom, bitmap) - } - } - } - } - - /** - * DrawBitmap - * - * @param canvas - * @param left - * @param top - * @param right - * @param bottom - * @param bitmap - */ - fun drawBitmapAtPosition( - canvas: Canvas, - left: Int, - top: Int, - right: Int, - bottom: Int, - bitmap: Bitmap? - ) { - var drawBitmap = bitmap - if (drawBitmap == null) { - if (multiImageData.defaultImageResId > 0) { - drawBitmap = - BitmapFactory.decodeResource( - mContext.resources, - multiImageData.defaultImageResId - ) - } - } - if (drawBitmap != null) { - val rect = Rect(left, top, right, bottom) - canvas.drawBitmap(drawBitmap, null, rect, null) - } - } - - @Throws(ExecutionException::class, InterruptedException::class) - private fun asyncLoadImage(imageUrl: Any, targetImageSize: Int): Bitmap { - return GlideEngine.loadBitmap(imageUrl, targetImageSize) - } - - fun setImageId(id: String) { - currentImageId = id - } - - fun getImageId(): String { - return currentImageId - } - - fun load(imageId: String?) { - if (multiImageData.size() == 0) { - // The image id when the request is initiated is inconsistent with the current image id, - // indicating that multiplexing has occurred, and the image should not be set at this time. - if (imageId != null && !TextUtils.equals(imageId, currentImageId)) { - return - } - GlideEngine.loadUserIcon(imageView, getDefaultImage()) - return - } - - if (multiImageData.size() == 1) { - // The image id when the request is initiated is inconsistent with the current image id, - // indicating that multiplexing has occurred, and the image should not be set at this time. - if (imageId != null && !TextUtils.equals(imageId, currentImageId)) { - return - } - GlideEngine.loadUserIcon(imageView, multiImageData.imageUrls!![0]) - return - } - - // Clear the content before loading images asynchronously to avoid flickering - clearImage() - - // Initialize the image information. Since it is asynchronous loading and synthesizing the avatar, - // a local object needs to be passed to the synthesis thread, which is only used in the asynchronous - // loading thread, so that when the image is reused, the external thread will not overwrite the local - // object by setting the url again. - var copyMultiImageData: MultiImageData - try { - copyMultiImageData = multiImageData.clone() - } catch (e: CloneNotSupportedException) { - e.printStackTrace() - val urlList = ArrayList() - if (multiImageData.imageUrls != null) { - urlList.addAll(multiImageData.imageUrls!!) - } - copyMultiImageData = MultiImageData(urlList, multiImageData.defaultImageResId) - } - - val gridParam = calculateGridParam(multiImageData.size()) - copyMultiImageData.rowCount = gridParam[0] - copyMultiImageData.columnCount = gridParam[1] - copyMultiImageData.targetImageSize = - (copyMultiImageData.maxWidth - (copyMultiImageData.columnCount + 1) * copyMultiImageData.gap) / - if (copyMultiImageData.columnCount == 1) 2 else copyMultiImageData.columnCount - - val finalImageId = imageId - val finalCopyMultiImageData = copyMultiImageData - - ThreadUtils.execute { - val file = File(TUIConfig.getImageBaseDir() + finalImageId) - var cacheBitmapExists = false - var existsBitmap: Bitmap? = null - if (file.exists() && file.isFile) { - val options = BitmapFactory.Options() - existsBitmap = BitmapFactory.decodeFile(file.path, options) - if (options.outWidth > 0 && options.outHeight > 0) { - cacheBitmapExists = true - } - } - if (!cacheBitmapExists) { - asyncLoadImageList(finalCopyMultiImageData) - val bitmap = synthesizeImageList(finalCopyMultiImageData) - ImageUtil.storeBitmap(file, bitmap) - ImageUtil.setGroupConversationAvatar(finalImageId!!, file.absolutePath) - ThreadUtils.postOnUiThread { - callback.onCall(bitmap, finalImageId) - } - } else { - val finalExistsBitmap = existsBitmap - ThreadUtils.postOnUiThread { - callback.onCall(finalExistsBitmap!!, finalImageId!!) - } - } - } - } - - fun clearImage() { - GlideEngine.clear(imageView) - } - - internal interface Callback { - fun onCall(bitmap: Bitmap, targetID: String) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/login/LocalMusicService.kt b/application/app/src/main/java/com/tencent/uikit/app/login/LocalMusicService.kt deleted file mode 100644 index 879ffe86..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/login/LocalMusicService.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.tencent.uikit.app.login - -import com.trtc.uikit.livekit.component.karaoke.store.ActionCallback -import com.trtc.uikit.livekit.component.karaoke.store.GetSongListCallBack -import com.trtc.uikit.livekit.component.karaoke.store.MusicCatalogService -import com.trtc.uikit.livekit.component.karaoke.store.utils.MusicInfo -import com.tencent.qcloud.tuikit.debug.GenerateTestUserSig - -class LocalMusicService : MusicCatalogService() { - - override fun getSongList(callback: GetSongListCallBack) { - val localList = ArrayList() - callback.onSuccess(localList) - } - - override fun generateUserSig( - userId: String, - callback: ActionCallback, - ) { - callback.onSuccess(GenerateTestUserSig.genTestUserSig(userId)) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/login/LoginActivity.kt b/application/app/src/main/java/com/tencent/uikit/app/login/LoginActivity.kt deleted file mode 100644 index 3ef13077..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/login/LoginActivity.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.tencent.uikit.app.login - -import android.content.Intent -import android.os.Bundle -import android.util.Log -import android.view.View -import android.widget.EditText -import androidx.lifecycle.lifecycleScope -import com.tencent.qcloud.tuicore.TUILogin -import com.tencent.qcloud.tuicore.util.SPUtils -import com.tencent.qcloud.tuikit.debug.GenerateTestUserSig -import com.tencent.qcloud.tuikit.tuicallkit.TUICallKit.Companion.createInstance -import com.tencent.uikit.app.R -import com.tencent.uikit.app.common.utils.DEMO_LOGIN_SUCCESS -import com.tencent.uikit.app.common.utils.KeyMetrics -import com.tencent.uikit.app.main.BaseActivity -import com.tencent.uikit.app.main.MainActivity -import io.trtc.tuikit.atomicx.widget.basicwidget.toast.AtomicToast -import io.trtc.tuikit.atomicxcore.api.CompletionHandler -import io.trtc.tuikit.atomicxcore.api.login.LoginStore -import kotlinx.coroutines.launch - -class LoginActivity : BaseActivity() { - companion object { - private const val TAG = "LoginActivity" - } - - private lateinit var editUserId: EditText - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (!isTaskRoot - && intent.hasCategory(Intent.CATEGORY_LAUNCHER) - && intent.action != null - && intent.action.equals(Intent.ACTION_MAIN) - ) { - finish() - return - } - setContentView(R.layout.app_activity_login) - initView() - } - - private fun initView() { - editUserId = findViewById(R.id.et_userId) - editUserId.setText(SPUtils.getInstance("app_uikit").getString("userId")) - findViewById(R.id.btn_login).setOnClickListener { - val userId = editUserId.text.toString().trim() - SPUtils.getInstance("app_uikit").put("userId", userId) - login(userId) - } - } - - private fun login(userId: String) { - if (userId.isEmpty()) { - AtomicToast.show( - this, - getString(R.string.app_user_id_is_empty), - AtomicToast.Style.ERROR - ) - return - } - val userSig = GenerateTestUserSig.genTestUserSig(userId) - LoginStore.shared.login(this, GenerateTestUserSig.SDKAPPID, userId, userSig, object : CompletionHandler { - override fun onSuccess() { - Log.i(TAG, "login onSuccess") - val instance = createInstance(application) - instance.enableFloatWindow(true) - instance.enableVirtualBackground(true) - instance.enableIncomingBanner(true) - instance.enableAITranscriber(true) - getUserInfo() - - KeyMetrics.reportAtomicMetrics(DEMO_LOGIN_SUCCESS) - } - - override fun onFailure(code: Int, desc: String) { - AtomicToast.show( - this@LoginActivity, - getString(R.string.app_toast_login_fail, code, desc), - AtomicToast.Style.ERROR - ) - Log.e(TAG, "login fail errorCode: $code errorMessage:$desc") - } - }) - TUILogin.login(this, GenerateTestUserSig.SDKAPPID, userId, userSig, null) - } - - private fun getUserInfo() { - lifecycleScope.launch { - LoginStore.shared.loginState.loginUserInfo.collect { loginUserInfo -> - loginUserInfo?.let { - if (it.userID.isEmpty()) { - return@collect - } - if (it.nickname.isNullOrEmpty() || it.avatarURL.isNullOrEmpty()) { - val intent = Intent(this@LoginActivity, RegisterActivity::class.java) - startActivity(intent) - finish() - } else { - val intent = Intent(this@LoginActivity, MainActivity::class.java) - startActivity(intent) - finish() - } - } - } - } - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/login/RegisterActivity.kt b/application/app/src/main/java/com/tencent/uikit/app/login/RegisterActivity.kt deleted file mode 100644 index 05c50ec0..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/login/RegisterActivity.kt +++ /dev/null @@ -1,164 +0,0 @@ -package com.tencent.uikit.app.login - -import android.content.Intent -import android.os.Bundle -import android.text.Editable -import android.text.TextWatcher -import android.util.Log -import android.widget.Button -import android.widget.EditText -import android.widget.TextView -import androidx.core.content.ContextCompat -import com.tencent.imsdk.v2.V2TIMCallback -import com.tencent.imsdk.v2.V2TIMUserFullInfo -import com.tencent.uikit.app.R -import com.tencent.uikit.app.main.BaseActivity -import com.tencent.uikit.app.main.MainActivity -import com.tencent.uikit.app.mine.UserManager -import io.trtc.tuikit.atomicx.widget.basicwidget.avatar.AtomicAvatar -import io.trtc.tuikit.atomicx.widget.basicwidget.avatar.AtomicAvatar.AvatarContent -import io.trtc.tuikit.atomicx.widget.basicwidget.toast.AtomicToast -import java.util.Random -import java.util.regex.Pattern - -class RegisterActivity : BaseActivity() { - companion object { - private const val TAG = "RegisterActivity" - - private val USER_AVATAR_ARRAY = arrayOf( - "https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar1.png", - "https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar2.png", - "https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar3.png", - "https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar4.png", - "https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar5.png" - ) - - private val CUSTOM_NAME_ARRAY = arrayOf( - R.string.app_custom_name_1, - R.string.app_custom_name_2, - R.string.app_custom_name_3, - R.string.app_custom_name_4, - R.string.app_custom_name_5 - ) - } - - private lateinit var imageAvatar: AtomicAvatar - private lateinit var editUserName: EditText - private lateinit var buttonRegister: Button - private lateinit var tvInputTips: TextView - private var avatarUrl: String = "" - private val random = Random() - - private fun startMainActivity() { - val intent = Intent(this@RegisterActivity, MainActivity::class.java) - startActivity(intent) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.app_activity_login_profile) - initView() - } - - private fun initView() { - imageAvatar = findViewById(R.id.iv_user_avatar) - editUserName = findViewById(R.id.et_user_name) - buttonRegister = findViewById(R.id.btn_register) - tvInputTips = findViewById(R.id.tv_tips_user_name) - - val index = random.nextInt(USER_AVATAR_ARRAY.size) - avatarUrl = USER_AVATAR_ARRAY[index] - imageAvatar.setContent(AvatarContent.URL(avatarUrl, R.drawable.app_avatar)) - - buttonRegister.setOnClickListener { - setProfile() - } - - val customNameIndex = random.nextInt(CUSTOM_NAME_ARRAY.size) - editUserName.setText(getString(CUSTOM_NAME_ARRAY[customNameIndex])) - val text = editUserName.text.toString() - if (text.isNotEmpty()) { - editUserName.setSelection(text.length) - } - - editUserName.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - buttonRegister.isEnabled = !s.isNullOrEmpty() - val editable = editUserName.text.toString() - val pattern = Pattern.compile("^[a-z0-9A-Z\\u4e00-\\u9fa5\\_]{2,20}$") - val matcher = pattern.matcher(editable) - if (!matcher.matches()) { - tvInputTips.setTextColor( - ContextCompat.getColor( - this@RegisterActivity, - R.color.app_color_input_no_match - ) - ) - } else { - tvInputTips.setTextColor( - ContextCompat.getColor( - this@RegisterActivity, - R.color.app_text_color_hint - ) - ) - } - } - - override fun afterTextChanged(s: Editable?) {} - }) - } - - private fun setProfile() { - val userName = editUserName.text.toString().trim() - if (userName.isEmpty()) { - AtomicToast.show( - this, - getString(R.string.app_hint_user_name), - AtomicToast.Style.ERROR, - duration = AtomicToast.Duration.LONG - ) - return - } - val reg = "^[a-z0-9A-Z\\u4e00-\\u9fa5\\_]{2,20}$" - if (!userName.matches(reg.toRegex())) { - tvInputTips.setTextColor( - ContextCompat.getColor( - this, - R.color.app_color_input_no_match - ) - ) - return - } - tvInputTips.setTextColor(ContextCompat.getColor(this, R.color.app_text_color_hint)) - val v2TIMUserFullInfo = V2TIMUserFullInfo() - v2TIMUserFullInfo.setFaceUrl(avatarUrl) - v2TIMUserFullInfo.setNickname(userName) - UserManager.getInstance().updateSelfUserInfo(v2TIMUserFullInfo, object : V2TIMCallback { - override fun onError(code: Int, desc: String?) { - Log.e(TAG, "set profile failed errorCode : $code errorMsg : $desc") - AtomicToast.show( - this@RegisterActivity, - getString(R.string.app_toast_failed_to_set, desc), - AtomicToast.Style.ERROR, - duration = AtomicToast.Duration.LONG - ) - startMainActivity() - finish() - } - - override fun onSuccess() { - Log.i(TAG, "set profile success.") - AtomicToast.show( - this@RegisterActivity, - getString(R.string.app_toast_register_success_and_logging_in), - AtomicToast.Style.SUCCESS, - duration = AtomicToast.Duration.LONG - ) - startMainActivity() - finish() - } - }) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/BaseActivity.kt b/application/app/src/main/java/com/tencent/uikit/app/main/BaseActivity.kt deleted file mode 100644 index 15c2e321..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/BaseActivity.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.tencent.uikit.app.main - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.graphics.Color -import android.os.Build -import android.os.Bundle -import android.view.MotionEvent -import android.view.View -import android.view.WindowManager -import android.view.inputmethod.InputMethodManager -import androidx.appcompat.app.AppCompatActivity -import androidx.localbroadcastmanager.content.LocalBroadcastManager -import com.tencent.qcloud.tuicore.TUILogin -import com.tencent.qcloud.tuicore.util.TUIBuild -import com.tencent.uikit.app.login.LoginActivity -import com.tencent.uikit.app.setting.LanguageSelectActivity - -open class BaseActivity : AppCompatActivity() { - - private val languageChangedReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - if (intent?.action == LanguageSelectActivity.LANGUAGE_CHANGED_ACTION) { - recreate() - } - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - checkUserLoginStatus(savedInstanceState) - initStatusBar() - hideSoftKeyboard() - - LocalBroadcastManager.getInstance(this).registerReceiver( - languageChangedReceiver, - IntentFilter(LanguageSelectActivity.LANGUAGE_CHANGED_ACTION) - ) - } - - private fun checkUserLoginStatus(savedInstanceState: Bundle?) { - if (savedInstanceState != null && !TUILogin.isUserLogined()) { - val loginIntent = Intent(this, LoginActivity::class.java).apply { - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) - } - startActivity(loginIntent) - finish() - } - } - - override fun onTouchEvent(event: MotionEvent?): Boolean { - try { - val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - currentFocus?.windowToken?.let { - imm.hideSoftInputFromWindow(it, 0) - } - } catch (_: Exception) { - } - return super.onTouchEvent(event) - } - - private fun initStatusBar() { - val window = window - if (TUIBuild.getVersionInt() >= Build.VERSION_CODES.LOLLIPOP) { - window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) - window.decorView.systemUiVisibility = - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) - window.statusBarColor = Color.TRANSPARENT - } else if (TUIBuild.getVersionInt() >= Build.VERSION_CODES.KITKAT) { - window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) - } - } - - protected fun hideSoftKeyboard() { - window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) - } - - override fun onDestroy() { - runCatching { - LocalBroadcastManager.getInstance(this).unregisterReceiver(languageChangedReceiver) - } - super.onDestroy() - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/MainActivity.kt b/application/app/src/main/java/com/tencent/uikit/app/main/MainActivity.kt deleted file mode 100644 index 30412fc4..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/MainActivity.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.tencent.uikit.app.main - -import android.content.Intent -import android.os.Bundle -import android.util.Log -import androidx.navigation.NavController -import androidx.navigation.Navigation -import androidx.navigation.fragment.NavHostFragment -import com.tencent.imsdk.v2.V2TIMUserFullInfo -import com.tencent.imsdk.v2.V2TIMValueCallback -import com.tencent.qcloud.tuicore.TUILogin -import com.tencent.uikit.app.R -import com.tencent.uikit.app.common.widget.RecycleFragmentNavigator -import com.tencent.uikit.app.login.LoginActivity -import com.tencent.uikit.app.mine.UserManager - - -class MainActivity : BaseActivity() { - companion object { - private const val TAG = "MainActivity" - } - - private var mNavController: NavController? = null - - public override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.app_activity_trtc_main) - - - mNavController = Navigation.findNavController(this, R.id.nav_host_fragment) - val navHostFragment: NavHostFragment? = - supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? - val recycleFragmentNavigator: RecycleFragmentNavigator = RecycleFragmentNavigator( - this, - supportFragmentManager, navHostFragment?.getId() ?: 0 - ) - mNavController?.navigatorProvider?.addNavigator(recycleFragmentNavigator) - mNavController?.setGraph(R.navigation.app_nav_main_graph) - } - - override fun onResume() { - super.onResume() - getUserInfo() - } - - private fun getUserInfo() { - if (!TUILogin.isUserLogined()) { - val intent = Intent(this@MainActivity, LoginActivity::class.java) - startActivity(intent) - finish() - return - } - UserManager.getInstance().getSelfUserInfo(object : V2TIMValueCallback { - override fun onError(errorCode: Int, errorMsg: String?) { - Log.e(TAG, "getUserInfo failed, code:$errorCode msg: $errorMsg") - } - - override fun onSuccess(timUserFullInfo: V2TIMUserFullInfo?) { - if (timUserFullInfo == null) { - Log.e(TAG, "getUserInfo result is empty") - return - } - } - }) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/MainFragment.kt b/application/app/src/main/java/com/tencent/uikit/app/main/MainFragment.kt deleted file mode 100644 index 6c2ea043..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/MainFragment.kt +++ /dev/null @@ -1,145 +0,0 @@ -package com.tencent.uikit.app.main - -import android.content.Intent -import android.os.Bundle -import android.text.TextUtils -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.navigation.Navigation -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.tencent.qcloud.tuicore.TUIConstants -import com.tencent.qcloud.tuicore.TUICore -import com.tencent.qcloud.tuicore.TUILogin -import com.tencent.qcloud.tuicore.TUIThemeManager -import com.tencent.qcloud.tuicore.interfaces.ITUINotification -import com.tencent.uikit.app.R -import com.tencent.uikit.app.common.utils.KeyMetrics -import io.trtc.tuikit.atomicx.widget.basicwidget.avatar.AtomicAvatar -import io.trtc.tuikit.atomicx.widget.basicwidget.avatar.AtomicAvatar.AvatarContent - -class MainFragment : Fragment() { - private var userCenter: AtomicAvatar? = null - private var recyclerMain: RecyclerView? = null - private var trtcMainAdapter: TRTCMainAdapter? = null - private val notification: ITUINotification = object : ITUINotification { - override fun onNotifyEvent(key: String?, subKey: String?, param: MutableMap) { - Log.i(TAG, "key=$key,subKey=$subKey,param=$param") - if (TextUtils.equals(param[TUIConstants.TUILogin.SELF_ID] as String?, TUILogin.getLoginUser())) { - userCenter?.setContent(AvatarContent.URL(TUILogin.getFaceUrl(), R.drawable.app_ic_avatar)) - } - } - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val rootView: View = inflater.inflate(R.layout.app_fragment_main, container, false) - initView(rootView) - registerEvent() - return rootView - } - - override fun onDestroyView() { - super.onDestroyView() - unRegisterEvent() - } - - private fun initView(rootView: View) { - val mainTitle = rootView.findViewById(R.id.img_main_icon) - recyclerMain = rootView.findViewById(R.id.rv_main_list) - mainTitle?.setBackgroundResource(R.drawable.app_title_zh) - if (TextUtils.equals(TUIThemeManager.getInstance().currentLanguage, "en")) { - mainTitle?.setBackgroundResource(R.drawable.app_title_en) - } - userCenter = rootView.findViewById(R.id.img_user_center) - userCenter?.setContent(AvatarContent.URL(TUILogin.getFaceUrl(), R.drawable.app_ic_avatar)) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val navController = Navigation.findNavController(view) - userCenter?.setOnClickListener { v: View? -> navController.navigate(R.id.mine_fragment) } - val trtcMainData = TRTCMainData() - trtcMainAdapter = TRTCMainAdapter( - TUIThemeManager.getInstance().currentLanguage, - trtcMainData.itemDataList as MutableList, object : TRTCMainAdapter.OnItemClickListener { - override fun onItemClick(mainItemData: MainItemData?) { - mainItemData?.let { item -> - item.itemType?.let { data -> - KeyMetrics.reportAtomicMetrics(data.reportEvent) - } - val type: Int = item.itemType?.type ?: 0 - val intent = Intent(context, item.itemTargetClass) - intent.putExtra("TITLE", getString(item.itemTitle)) - intent.putExtra("TYPE", type) - startActivity(intent) - } - } - }) - val gridLayoutManager = GridLayoutManager(getContext(), 2) - recyclerMain?.setLayoutManager(gridLayoutManager) - recyclerMain?.setAdapter(trtcMainAdapter) - } - - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - userCenter?.setContent(AvatarContent.URL(TUILogin.getFaceUrl(), R.drawable.app_ic_avatar)) - } - - private fun registerEvent() { - TUICore.registerEvent( - TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED, - TUIConstants.TUILogin.EVENT_SUB_KEY_USER_INFO_UPDATED, notification - ) - } - - private fun unRegisterEvent() { - TUICore.unRegisterEvent( - TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED, - TUIConstants.TUILogin.EVENT_SUB_KEY_USER_INFO_UPDATED, notification - ) - } - - companion object { - private const val TAG = "MainFragment" - const val url = "https://cloud.tencent.com/act/event/report-platform" - - } - - private data class SimpleItem( - val iconRes: Int, - val title: String, - val subtitle: String - ) - - private class SimpleAdapter( - private val items: List, - private val onItemClick: () -> Unit - ) : RecyclerView.Adapter() { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleVH { - val view = LayoutInflater.from(parent.context).inflate(R.layout.app_main_item, parent, false) - return SimpleVH(view) - } - - override fun onBindViewHolder(holder: SimpleVH, position: Int) { - val item = items[position] - holder.icon.setImageResource(item.iconRes) - holder.title.text = item.title - holder.subtitle.text = item.subtitle - holder.itemView.setOnClickListener { onItemClick() } - } - - override fun getItemCount(): Int = items.size - - class SimpleVH(itemView: View) : RecyclerView.ViewHolder(itemView) { - val icon: ImageView = itemView.findViewById(R.id.img_main_icon) - val title: TextView = itemView.findViewById(R.id.tv_main_title) - val subtitle: TextView = itemView.findViewById(R.id.tv_main_subtitle) - } - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/MainItemData.kt b/application/app/src/main/java/com/tencent/uikit/app/main/MainItemData.kt deleted file mode 100644 index f4f13dd0..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/MainItemData.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tencent.uikit.app.main - -data class MainItemData( - val itemType: MainTypeEnum?, - val itemResId: Int, - val itemTitle: Int, - val itemSubTitle: Int, - val itemTargetClass: Class<*>?, - val category: Category? -) { - enum class Category { - UNDEFINED, - KIT, - HOT - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/MainTypeEnum.kt b/application/app/src/main/java/com/tencent/uikit/app/main/MainTypeEnum.kt deleted file mode 100644 index 82468aaf..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/MainTypeEnum.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tencent.uikit.app.main - -import com.tencent.uikit.app.common.utils.DEMO_CLICK_CALL -import com.tencent.uikit.app.common.utils.DEMO_CLICK_LIVE -import com.tencent.uikit.app.common.utils.DEMO_CLICK_ROOM - -enum class MainTypeEnum(val type: Int, val properties: String, val reportEvent: Int = -1) { - TYPE_ITEM_MEETING(100, "conference", DEMO_CLICK_ROOM), - TYPE_ITEM_CALL(104, "call", DEMO_CLICK_CALL), - TYPE_ITEM_LIVE(106, "live", DEMO_CLICK_LIVE), - TYPE_ITEM_VOICE(107, "voice"), - TYPE_ITEM_CHAT(109, "chat") -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/TRTCMainAdapter.kt b/application/app/src/main/java/com/tencent/uikit/app/main/TRTCMainAdapter.kt deleted file mode 100644 index 46ae534a..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/TRTCMainAdapter.kt +++ /dev/null @@ -1,146 +0,0 @@ -package com.tencent.uikit.app.main - -import android.content.res.Resources -import android.text.TextUtils -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.recyclerview.widget.RecyclerView -import com.tencent.uikit.app.R - -class TRTCMainAdapter( - private val currentLanguage: String?, - private val itemDataList: MutableList, - private val onItemClickListener: OnItemClickListener -) : RecyclerView.Adapter() { - - override fun getItemViewType(position: Int): Int { - if (position == itemCount - 1) { - return ITEM_TYPE_FOOTER - } - return ITEM_TYPE_ITEM - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - val context = parent.context - val inflater = LayoutInflater.from(context) - if (viewType == ITEM_TYPE_ITEM) { - val view: View = inflater.inflate(R.layout.app_main_item, parent, false) - return ItemViewHolder(view) - } else if (viewType == ITEM_TYPE_WEB_VIEW) { - val view: View = inflater.inflate(R.layout.app_item_web_view, parent, false) - return WebViewHolder(view) - } else { - val view = View(parent.context) - return FooterViewHolder(view) - } - } - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - if (holder is ItemViewHolder) { - val item: MainItemData? = itemDataList[position] - holder.bind(item, onItemClickListener) - } else if (holder is WebViewHolder) { - val item: MainItemData? = itemDataList[position] - holder.bind(item, currentLanguage, onItemClickListener) - } - } - - override fun getItemCount(): Int { - return itemDataList.size + 1 - } - - interface OnItemClickListener { - fun onItemClick(mainItemData: MainItemData?) - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val imageIcon: ImageView = itemView.findViewById(R.id.img_main_icon) - private val textTitle: TextView = itemView.findViewById(R.id.tv_main_title) - private val textSubTitle: TextView = itemView.findViewById(R.id.tv_main_subtitle) - private val constraintItem: ConstraintLayout = itemView.findViewById(R.id.cl_main_item) - - fun bind( - mainItemData: MainItemData?, - onItemClickListener: OnItemClickListener - ) { - if (mainItemData == null) { - return - } - itemView.setOnClickListener { v: View? -> - onItemClickListener.onItemClick( - mainItemData - ) - } - - constraintItem.setBackgroundResource( - if (mainItemData.category === MainItemData.Category.KIT) - R.drawable.app_bg_main_kit_item - else - R.drawable.app_bg_main_item - ) - textTitle.setText(mainItemData.itemTitle) - imageIcon.setImageResource(mainItemData.itemResId) - textSubTitle.setText(mainItemData.itemSubTitle) - } - } - - class WebViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val textTitle: TextView = itemView.findViewById(R.id.tv_main_title) - private val textSubTitle: TextView = itemView.findViewById(R.id.tv_main_subtitle) - - fun bind( - mainItemData: MainItemData?, - currentLanguage: String?, - onItemClickListener: OnItemClickListener - ) { - if (mainItemData == null) { - return - } - val layoutParams: ViewGroup.LayoutParams? - if (TextUtils.equals(currentLanguage, ENGLISH_LANGUAGE_CODE)) { - layoutParams = LinearLayout.LayoutParams( - dp2px(ENGLISH_TEXT_WIDTH_DP.toFloat()), - dp2px(ENGLISH_TEXT_HEIGHT_DP.toFloat()) - ) - } else { - layoutParams = LinearLayout.LayoutParams( - dp2px(DEFAULT_TEXT_WIDTH_DP.toFloat()), - dp2px(DEFAULT_TEXT_HEIGHT_DP.toFloat()) - ) - } - itemView.setOnClickListener(View.OnClickListener { v: View? -> - onItemClickListener.onItemClick( - mainItemData - ) - }) - textTitle.setText(mainItemData.itemTitle) - textSubTitle.setText(mainItemData.itemSubTitle) - } - } - - class FooterViewHolder(view: View) : RecyclerView.ViewHolder(view) - companion object { - const val ITEM_TYPE_ITEM: Int = 0 - const val ITEM_TYPE_FOOTER: Int = 1 - const val ITEM_TYPE_WEB_VIEW: Int = 2 - private const val ENGLISH_LANGUAGE_CODE = "en" - private const val ENGLISH_TEXT_WIDTH_DP = 36 - private const val ENGLISH_TEXT_HEIGHT_DP = 18 - private const val DEFAULT_TEXT_WIDTH_DP = 32 - private const val DEFAULT_TEXT_HEIGHT_DP = 18 - private fun dp2px(dp: Float): Int { - return TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, - dp, - Resources.getSystem().displayMetrics - ) - .toInt() - } - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/TRTCMainData.kt b/application/app/src/main/java/com/tencent/uikit/app/main/TRTCMainData.kt deleted file mode 100644 index 82b9fef5..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/TRTCMainData.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.tencent.uikit.app.main - -import com.tencent.uikit.app.R -import com.tencent.uikit.app.main.call.GroupCallActivity -import com.tencent.uikit.app.main.live.LiveActivity -import com.trtc.uikit.roomkit.RoomHomeActivity - -class TRTCMainData { - val itemDataList = ArrayList() - - init { - itemDataList.add( - MainItemData( - MainTypeEnum.TYPE_ITEM_CALL, R.drawable.app_ic_main_call, R.string.app_main_item_call, - R.string.app_main_item_call_sub, GroupCallActivity::class.java, MainItemData.Category.KIT - ) - ) - itemDataList.add( - MainItemData( - MainTypeEnum.TYPE_ITEM_LIVE, R.drawable.app_ic_main_live, R.string.app_main_item_live, - R.string.app_main_item_live_sub, LiveActivity::class.java, MainItemData.Category.KIT - ) - ) - itemDataList.add( - MainItemData( - MainTypeEnum.TYPE_ITEM_MEETING, R.drawable.app_ic_main_meeting, R.string.app_main_item_meeting, - R.string.app_main_item_meeting_sub, RoomHomeActivity::class.java, MainItemData.Category.KIT - ) - ) - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/call/GroupCallActivity.kt b/application/app/src/main/java/com/tencent/uikit/app/main/call/GroupCallActivity.kt deleted file mode 100644 index d5192e60..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/call/GroupCallActivity.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.tencent.uikit.app.main.call - -import android.content.Intent -import android.os.Bundle -import android.text.TextUtils -import android.view.View -import android.widget.EditText -import android.widget.RadioGroup -import android.widget.RelativeLayout -import com.tencent.qcloud.tuicore.TUILogin -import com.tencent.qcloud.tuikit.tuicallkit.TUICallKit -import io.trtc.tuikit.atomicx.widget.basicwidget.toast.AtomicToast -import com.tencent.uikit.app.R -import com.tencent.uikit.app.main.BaseActivity -import com.trtc.tuikit.common.util.ToastUtil -import io.trtc.tuikit.atomicxcore.api.call.CallMediaType -import io.trtc.tuikit.atomicxcore.api.call.CallParams -import java.util.Arrays - -class GroupCallActivity : BaseActivity() { - private var editGroupId: EditText? = null - private var editUserList: EditText? = null - private var mediaType = CallMediaType.Audio - private var isOptionalParamViewExpand = false - - public override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.app_activity_group_call) - initView() - } - - private fun initView() { - editUserList = findViewById(R.id.et_user_id_list) - editGroupId = findViewById(R.id.et_group_id) - - findViewById(R.id.iv_back).setOnClickListener { onBackPressed() } - findViewById(R.id.btn_call).setOnClickListener { startGroupCall() } - findViewById(R.id.ll_setting).setOnClickListener { - startActivity(Intent(this, SettingsActivity::class.java)) - } - findViewById(R.id.rg_media_type).setOnCheckedChangeListener { group: RadioGroup?, checkedId: Int -> - mediaType = if (checkedId == R.id.rb_video) { - CallMediaType.Video - } else { - CallMediaType.Audio - } - } - val layoutChatGroupId: RelativeLayout = findViewById(R.id.rl_chat_group_id) - findViewById(R.id.ll_option).setOnClickListener { - layoutChatGroupId.visibility = if (!isOptionalParamViewExpand) View.VISIBLE else View.GONE - isOptionalParamViewExpand = !isOptionalParamViewExpand - } - } - - private fun startGroupCall() { - val userList = editUserList!!.getText().toString() - - if (TextUtils.isEmpty(userList)) { - AtomicToast.show( - this, - getString(R.string.app_please_input_user_id_list), - AtomicToast.Style.ERROR - ) - return - } - var userIdList: MutableList = mutableListOf() - if (userList.contains(",")) { - userIdList = - Arrays.asList(*userList.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) - } else if (userList.contains(",")) { - userIdList = - Arrays.asList(*userList.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) - } else { - userIdList = Arrays.asList(userList) - } - var callParams = createCallParams() - if (callParams == null) { - callParams = CallParams() - } - callParams.chatGroupId = editGroupId!!.getText().toString() - TUICallKit.createInstance(this).calls(userIdList, mediaType, callParams, null) - } - - private fun createCallParams(): CallParams? { - try { - if (SettingsConfig.callTimeOut !== 30 || !TextUtils.isEmpty(SettingsConfig.userData) || !TextUtils.isEmpty( - SettingsConfig.offlineParams - ) || SettingsConfig.intRoomId !== 0 || !TextUtils.isEmpty(SettingsConfig.strRoomId) - ) { - val callParams = CallParams() - callParams.timeout = SettingsConfig.callTimeOut - callParams.userData = SettingsConfig.userData - if (!TextUtils.isEmpty(SettingsConfig.strRoomId)) { - callParams.roomId = SettingsConfig.strRoomId - } - return callParams - } - } catch (e: Exception) { - } - return null - } -} \ No newline at end of file diff --git a/application/app/src/main/java/com/tencent/uikit/app/main/call/SettingDetailAcitivity.kt b/application/app/src/main/java/com/tencent/uikit/app/main/call/SettingDetailAcitivity.kt deleted file mode 100644 index 84030552..00000000 --- a/application/app/src/main/java/com/tencent/uikit/app/main/call/SettingDetailAcitivity.kt +++ /dev/null @@ -1,112 +0,0 @@ -package com.tencent.uikit.app.main.call - -import android.os.Bundle -import android.view.KeyEvent -import android.view.inputmethod.EditorInfo -import android.widget.Button -import android.widget.EditText -import android.widget.ImageView -import android.widget.TextView -import com.tencent.qcloud.tuicore.TUILogin -import com.tencent.qcloud.tuikit.tuicallkit.TUICallKit.Companion.createInstance -import com.tencent.uikit.app.R -import com.tencent.uikit.app.main.BaseActivity -import io.trtc.tuikit.atomicx.widget.basicwidget.toast.AtomicToast -import io.trtc.tuikit.atomicxcore.api.CompletionHandler - -class SettingDetailActivity : BaseActivity() { - private var editContent: EditText? = null - private var itemType = ITEM_USER_DATA - - public override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.app_activity_settings_detail) - initBundleData() - initView() - } - - private fun initBundleData() { - itemType = getIntent().getStringExtra(ITEM_KEY).toString() - } - - private fun initView() { - editContent = findViewById(R.id.et_content) - when (itemType) { - ITEM_USER_DATA -> { - editContent?.setText(SettingsConfig.userData) - editContent?.setHint(getString(R.string.app_invite_cmd_extra_info)) - } - - ITEM_OFFLINE_MESSAGE -> { - editContent?.setText(SettingsConfig.offlineParams) - editContent?.setHint(getString(R.string.app_offline_message_json_string)) - } - - ITEM_AVATAR -> { - editContent?.setText(TUILogin.getFaceUrl()) - editContent?.setHint(getString(R.string.app_avatar)) - } - - ITEM_RING_PATH -> { - editContent?.setText(SettingsConfig.ringPath) - editContent?.setHint(getString(R.string.app_set_ring_path)) - } - - else -> {} - } - findViewById(R.id.iv_back).setOnClickListener { finish() } - findViewById