├── .gitignore
├── Android
├── app
│ ├── .gitignore
│ ├── libs
│ │ └── PLACEHOLDER
│ ├── src
│ │ ├── main
│ │ │ ├── assets
│ │ │ │ └── mixing.mp3
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_ban.png
│ │ │ │ │ ├── ic_close.png
│ │ │ │ │ ├── ic_exit.png
│ │ │ │ │ ├── ic_gift.png
│ │ │ │ │ ├── ic_join.png
│ │ │ │ │ ├── ic_effect.png
│ │ │ │ │ ├── ic_mic_off.png
│ │ │ │ │ ├── ic_mic_on.png
│ │ │ │ │ ├── ic_unkown.png
│ │ │ │ │ ├── ic_audience.png
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── ic_mixing_off.png
│ │ │ │ │ ├── ic_mixing_on.png
│ │ │ │ │ ├── ic_speaker_on.png
│ │ │ │ │ ├── ic_speaker_off.png
│ │ │ │ │ ├── ic_launcher_round.png
│ │ │ │ │ ├── ic_mic_off_little.png
│ │ │ │ │ └── ic_mic_on_little.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ ├── bg_channel_0.jpg
│ │ │ │ │ ├── bg_channel_1.jpg
│ │ │ │ │ ├── bg_channel_2.jpg
│ │ │ │ │ ├── bg_channel_3.jpg
│ │ │ │ │ ├── bg_channel_4.jpg
│ │ │ │ │ ├── img_avatar_0.jpg
│ │ │ │ │ ├── img_avatar_1.jpg
│ │ │ │ │ ├── img_avatar_10.jpg
│ │ │ │ │ ├── img_avatar_11.jpg
│ │ │ │ │ ├── img_avatar_2.jpg
│ │ │ │ │ ├── img_avatar_3.png
│ │ │ │ │ ├── img_avatar_4.jpg
│ │ │ │ │ ├── img_avatar_5.jpg
│ │ │ │ │ ├── img_avatar_6.jpg
│ │ │ │ │ ├── img_avatar_7.jpg
│ │ │ │ │ ├── img_avatar_8.jpg
│ │ │ │ │ ├── img_avatar_9.jpg
│ │ │ │ │ ├── img_channel_0.png
│ │ │ │ │ ├── img_channel_1.png
│ │ │ │ │ ├── img_channel_2.png
│ │ │ │ │ ├── img_channel_3.png
│ │ │ │ │ ├── img_channel_4.png
│ │ │ │ │ ├── bg_channel_list.jpg
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── drawable
│ │ │ │ │ ├── bg_seat_grid_item.xml
│ │ │ │ │ ├── bg_member_dialog.xml
│ │ │ │ │ ├── bg_radius_container.xml
│ │ │ │ │ ├── selector_mixing.xml
│ │ │ │ │ ├── selector_changer_rb.xml
│ │ │ │ │ ├── bg_channel_grid_item.xml
│ │ │ │ │ ├── bg_member_item_btn.xml
│ │ │ │ │ ├── bg_seat_item.xml
│ │ │ │ │ ├── inset_divider.xml
│ │ │ │ │ ├── bg_gift_container.xml
│ │ │ │ │ ├── bg_changer_item_selected.xml
│ │ │ │ │ ├── bg_changer_item_normal.xml
│ │ │ │ │ ├── bg_changer_rb_checked.xml
│ │ │ │ │ ├── bg_changer_title.xml
│ │ │ │ │ └── bg_changer_rb_normal.xml
│ │ │ │ ├── color
│ │ │ │ │ └── selector_changer_rb.xml
│ │ │ │ ├── values
│ │ │ │ │ ├── ids.xml
│ │ │ │ │ ├── styles.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── strings_config.xml
│ │ │ │ │ ├── arrays.xml
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── dimens.xml
│ │ │ │ ├── layout
│ │ │ │ │ ├── layout_item_changer.xml
│ │ │ │ │ ├── layout_item_channel.xml
│ │ │ │ │ ├── activity_channel_grid.xml
│ │ │ │ │ ├── layout_item_seat.xml
│ │ │ │ │ ├── layout_item_message.xml
│ │ │ │ │ ├── dialog_member_list.xml
│ │ │ │ │ ├── dialog_changer_grid.xml
│ │ │ │ │ ├── layout_gift.xml
│ │ │ │ │ ├── layout_item_member.xml
│ │ │ │ │ ├── activity_chat_room.xml
│ │ │ │ │ └── layout_chat_room_bottom.xml
│ │ │ │ └── values-zh
│ │ │ │ │ └── strings.xml
│ │ │ ├── java
│ │ │ │ └── io
│ │ │ │ │ └── agora
│ │ │ │ │ └── chatroom
│ │ │ │ │ ├── manager
│ │ │ │ │ ├── MessageManager.java
│ │ │ │ │ └── ChatRoomEventListener.java
│ │ │ │ │ ├── model
│ │ │ │ │ ├── Constant.java
│ │ │ │ │ ├── Seat.java
│ │ │ │ │ ├── AttributeKey.java
│ │ │ │ │ ├── Channel.java
│ │ │ │ │ ├── Member.java
│ │ │ │ │ └── Message.java
│ │ │ │ │ ├── ChatRoomApplication.java
│ │ │ │ │ ├── widget
│ │ │ │ │ ├── FixedRatioImageView.java
│ │ │ │ │ ├── GiftPopView.java
│ │ │ │ │ ├── VoiceChangerGridRecyclerView.java
│ │ │ │ │ └── VoiceChangerDialog.java
│ │ │ │ │ ├── util
│ │ │ │ │ ├── MemberUtil.java
│ │ │ │ │ └── AlertUtil.java
│ │ │ │ │ ├── activity
│ │ │ │ │ └── ChannelGridActivity.java
│ │ │ │ │ └── adapter
│ │ │ │ │ ├── MessageListAdapter.java
│ │ │ │ │ ├── VoiceChangerGridAdapter.java
│ │ │ │ │ ├── ChannelGridAdapter.java
│ │ │ │ │ └── SeatGridAdapter.java
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── io
│ │ │ │ └── agora
│ │ │ │ └── chatroom
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── io
│ │ │ └── agora
│ │ │ └── chatroom
│ │ │ └── ExampleInstrumentedTest.java
│ └── build.gradle
├── popmenu
│ ├── .gitignore
│ ├── src
│ │ └── main
│ │ │ ├── res
│ │ │ ├── layout
│ │ │ │ └── layout_menu_item.xml
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── attrs.xml
│ │ │ │ └── styles.xml
│ │ │ └── drawable
│ │ │ │ └── bg_menu.xml
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ └── me
│ │ │ └── kareluo
│ │ │ └── ui
│ │ │ ├── OptionItemView.java
│ │ │ ├── PopVerticalScrollView.java
│ │ │ └── PopHorizontalScrollView.java
│ ├── build.gradle
│ └── proguard-rules.pro
├── settings.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── build.gradle
├── .gitignore
├── gradle.properties
├── ci.env.py
└── gradlew.bat
├── iOS
├── .gitignore
├── AgoraChatRoom
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── ic_ban.imageset
│ │ │ ├── ic_ban.png
│ │ │ └── Contents.json
│ │ ├── ic_close.imageset
│ │ │ ├── ic_close.png
│ │ │ └── Contents.json
│ │ ├── ic_exit.imageset
│ │ │ ├── ic_exit.png
│ │ │ └── Contents.json
│ │ ├── ic_gift.imageset
│ │ │ ├── ic_gift.png
│ │ │ └── Contents.json
│ │ ├── ic_join.imageset
│ │ │ ├── ic_join.png
│ │ │ └── Contents.json
│ │ ├── ic_create.imageset
│ │ │ ├── ic_create.png
│ │ │ └── Contents.json
│ │ ├── ic_effect.imageset
│ │ │ ├── ic_effect.png
│ │ │ └── Contents.json
│ │ ├── ic_mic_on.imageset
│ │ │ ├── ic_mic_on.png
│ │ │ └── Contents.json
│ │ ├── ic_unkown.imageset
│ │ │ ├── ic_unkown.png
│ │ │ └── Contents.json
│ │ ├── ic_mic_off.imageset
│ │ │ ├── ic_mic_off.png
│ │ │ └── Contents.json
│ │ ├── ic_audience.imageset
│ │ │ ├── ic_audience.png
│ │ │ └── Contents.json
│ │ ├── bg_channel_0.imageset
│ │ │ ├── bg_channel_0.jpg
│ │ │ └── Contents.json
│ │ ├── bg_channel_1.imageset
│ │ │ ├── bg_channel_1.jpg
│ │ │ └── Contents.json
│ │ ├── bg_channel_2.imageset
│ │ │ ├── bg_channel_2.jpg
│ │ │ └── Contents.json
│ │ ├── bg_channel_3.imageset
│ │ │ ├── bg_channel_3.jpg
│ │ │ └── Contents.json
│ │ ├── bg_channel_4.imageset
│ │ │ ├── bg_channel_4.jpg
│ │ │ └── Contents.json
│ │ ├── ic_mixing_off.imageset
│ │ │ ├── ic_mixing_off.png
│ │ │ └── Contents.json
│ │ ├── ic_mixing_on.imageset
│ │ │ ├── ic_mixing_on.png
│ │ │ └── Contents.json
│ │ ├── ic_speaker_on.imageset
│ │ │ ├── ic_speaker_on.png
│ │ │ └── Contents.json
│ │ ├── img_channel_0.imageset
│ │ │ ├── img_channel_0.png
│ │ │ └── Contents.json
│ │ ├── img_channel_1.imageset
│ │ │ ├── img_channel_1.png
│ │ │ └── Contents.json
│ │ ├── img_channel_2.imageset
│ │ │ ├── img_channel_2.png
│ │ │ └── Contents.json
│ │ ├── img_channel_3.imageset
│ │ │ ├── img_channel_3.png
│ │ │ └── Contents.json
│ │ ├── img_channel_4.imageset
│ │ │ ├── img_channel_4.png
│ │ │ └── Contents.json
│ │ ├── img_header_0.imageset
│ │ │ ├── img_header_0.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_1.imageset
│ │ │ ├── img_header_1.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_10.imageset
│ │ │ ├── img_header_10.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_11.imageset
│ │ │ ├── img_header_11.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_2.imageset
│ │ │ ├── img_header_2.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_3.imageset
│ │ │ ├── img_header_3.png
│ │ │ └── Contents.json
│ │ ├── img_header_4.imageset
│ │ │ ├── img_header_4.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_5.imageset
│ │ │ ├── img_header_5.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_6.imageset
│ │ │ ├── img_header_6.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_7.imageset
│ │ │ ├── img_header_7.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_8.imageset
│ │ │ ├── img_header_8.jpg
│ │ │ └── Contents.json
│ │ ├── img_header_9.imageset
│ │ │ ├── img_header_9.jpg
│ │ │ └── Contents.json
│ │ ├── ic_speaker_off.imageset
│ │ │ ├── ic_speaker_off.png
│ │ │ └── Contents.json
│ │ ├── bg_channel_list.imageset
│ │ │ ├── bg_channel_list.jpg
│ │ │ └── Contents.json
│ │ ├── ic_mic_on_little.imageset
│ │ │ ├── ic_mic_on_little.png
│ │ │ └── Contents.json
│ │ ├── ic_mic_off_little.imageset
│ │ │ ├── ic_mic_off_little.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Sound Horizon - 記憶の水底.mp3
│ ├── Channel.swift
│ ├── Seat.swift
│ ├── MessageManager.swift
│ ├── ChannelCell.swift
│ ├── Constant.swift
│ ├── AppDelegate.swift
│ ├── NavigationController.swift
│ ├── KeyCenter.swift
│ ├── AttributeKey.swift
│ ├── VoiceChangerCell.swift
│ ├── zh-Hans.lproj
│ │ ├── Main.strings
│ │ ├── Localizable.strings
│ │ └── LaunchScreen.storyboard
│ ├── MessageCell.swift
│ ├── Member.swift
│ ├── CustomView.swift
│ ├── MessageTableViewController.swift
│ ├── en.lproj
│ │ └── Localizable.strings
│ ├── AlertUtil.swift
│ ├── Message.swift
│ ├── Info.plist
│ ├── GiftPopView.swift
│ ├── MemberCell.swift
│ ├── SeatCollectionViewController.swift
│ ├── VoiceChanger.swift
│ ├── ChannelViewController.swift
│ ├── MemberViewController.swift
│ ├── MemberUtil.swift
│ └── VoiceChangerViewController.swift
├── AgoraChatRoom.xcodeproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── ci.env.py
├── Image
├── sdk.png
├── appid.jpg
├── sdk.en.png
└── appid.en.jpg
├── azure-pipelines.yml
└── cicd
└── templates
├── build-android.yml
└── build-ios.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
--------------------------------------------------------------------------------
/Android/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Android/popmenu/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Android/app/libs/PLACEHOLDER:
--------------------------------------------------------------------------------
1 | agora-rtc-sdk.jar
2 |
--------------------------------------------------------------------------------
/Android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':popmenu'
2 |
--------------------------------------------------------------------------------
/iOS/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | *.xcuserdatad
3 | *.xcscmblueprint
4 | libs/
--------------------------------------------------------------------------------
/Image/sdk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Image/sdk.png
--------------------------------------------------------------------------------
/Image/appid.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Image/appid.jpg
--------------------------------------------------------------------------------
/Image/sdk.en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Image/sdk.en.png
--------------------------------------------------------------------------------
/Image/appid.en.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Image/appid.en.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Android/app/src/main/assets/mixing.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/assets/mixing.mp3
--------------------------------------------------------------------------------
/Android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Sound Horizon - 記憶の水底.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Sound Horizon - 記憶の水底.mp3
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_ban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_ban.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_close.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_exit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_exit.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_gift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_gift.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_join.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_join.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_effect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_effect.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_mic_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_mic_off.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_mic_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_mic_on.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_unkown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_unkown.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_audience.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_audience.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_mixing_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_mixing_off.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_mixing_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_mixing_on.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_speaker_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_speaker_on.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_speaker_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_speaker_off.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_0.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_1.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_2.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_3.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_4.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_0.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_1.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_10.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_11.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_2.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_3.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_4.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_5.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_6.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_7.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_8.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_avatar_9.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_channel_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_channel_0.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_channel_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_channel_1.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_channel_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_channel_2.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_channel_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_channel_3.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/img_channel_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/img_channel_4.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_mic_off_little.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_mic_off_little.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-hdpi/ic_mic_on_little.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-hdpi/ic_mic_on_little.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_list.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/bg_channel_list.jpg
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_ban.imageset/ic_ban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_ban.imageset/ic_ban.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_close.imageset/ic_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_close.imageset/ic_close.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_exit.imageset/ic_exit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_exit.imageset/ic_exit.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_gift.imageset/ic_gift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_gift.imageset/ic_gift.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_join.imageset/ic_join.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_join.imageset/ic_join.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_create.imageset/ic_create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_create.imageset/ic_create.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_effect.imageset/ic_effect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_effect.imageset/ic_effect.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_on.imageset/ic_mic_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_on.imageset/ic_mic_on.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_unkown.imageset/ic_unkown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_unkown.imageset/ic_unkown.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_off.imageset/ic_mic_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_off.imageset/ic_mic_off.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_audience.imageset/ic_audience.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_audience.imageset/ic_audience.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_0.imageset/bg_channel_0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_0.imageset/bg_channel_0.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_1.imageset/bg_channel_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_1.imageset/bg_channel_1.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_2.imageset/bg_channel_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_2.imageset/bg_channel_2.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_3.imageset/bg_channel_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_3.imageset/bg_channel_3.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_4.imageset/bg_channel_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_4.imageset/bg_channel_4.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mixing_off.imageset/ic_mixing_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_mixing_off.imageset/ic_mixing_off.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mixing_on.imageset/ic_mixing_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_mixing_on.imageset/ic_mixing_on.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_speaker_on.imageset/ic_speaker_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_speaker_on.imageset/ic_speaker_on.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_0.imageset/img_channel_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_channel_0.imageset/img_channel_0.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_1.imageset/img_channel_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_channel_1.imageset/img_channel_1.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_2.imageset/img_channel_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_channel_2.imageset/img_channel_2.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_3.imageset/img_channel_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_channel_3.imageset/img_channel_3.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_4.imageset/img_channel_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_channel_4.imageset/img_channel_4.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_0.imageset/img_header_0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_0.imageset/img_header_0.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_1.imageset/img_header_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_1.imageset/img_header_1.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_10.imageset/img_header_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_10.imageset/img_header_10.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_11.imageset/img_header_11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_11.imageset/img_header_11.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_2.imageset/img_header_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_2.imageset/img_header_2.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_3.imageset/img_header_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_3.imageset/img_header_3.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_4.imageset/img_header_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_4.imageset/img_header_4.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_5.imageset/img_header_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_5.imageset/img_header_5.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_6.imageset/img_header_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_6.imageset/img_header_6.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_7.imageset/img_header_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_7.imageset/img_header_7.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_8.imageset/img_header_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_8.imageset/img_header_8.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_9.imageset/img_header_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/img_header_9.imageset/img_header_9.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_speaker_off.imageset/ic_speaker_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_speaker_off.imageset/ic_speaker_off.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_list.imageset/bg_channel_list.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_list.imageset/bg_channel_list.jpg
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_on_little.imageset/ic_mic_on_little.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_on_little.imageset/ic_mic_on_little.png
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_off_little.imageset/ic_mic_off_little.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AgoraIO-Usecase/Chatroom/HEAD/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_off_little.imageset/ic_mic_off_little.png
--------------------------------------------------------------------------------
/Android/popmenu/src/main/res/layout/layout_menu_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_seat_grid_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_member_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_radius_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Mar 28 17:19:53 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/Android/popmenu/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 7dp
4 | 7dp
5 |
--------------------------------------------------------------------------------
/Android/popmenu/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/color/selector_changer_rb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/selector_mixing.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Channel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Channel.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/5.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct Channel {
12 | var drawableRes: UIImage
13 | var backgroundRes: UIImage
14 | var name: String
15 | }
16 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/selector_changer_rb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_channel_grid_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_member_item_btn.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_seat_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/inset_divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Android/popmenu/src/main/res/drawable/bg_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_ban.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_ban.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_close.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_create.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_create.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_effect.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_effect.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_exit.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_exit.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_gift.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_gift.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_join.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_join.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_on.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_mic_on.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_unkown.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_unkown.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_audience.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_audience.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_off.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_mic_off.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_0.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bg_channel_0.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bg_channel_1.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bg_channel_2.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bg_channel_3.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bg_channel_4.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mixing_off.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_mixing_off.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mixing_on.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_mixing_on.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_speaker_off.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_speaker_off.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_speaker_on.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_speaker_on.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_0.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_channel_0.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_channel_1.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_channel_2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_channel_3.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_channel_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_channel_4.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_0.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_0.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_1.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_10.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_10.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_11.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_11.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_2.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_3.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_4.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_5.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_6.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_7.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_8.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_8.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/img_header_9.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_header_9.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/bg_channel_list.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bg_channel_list.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_on_little.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_mic_on_little.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/ic_mic_off_little.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "ic_mic_off_little.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Seat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Seat.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/22.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct Seat: Codable {
12 | var userId: String?
13 | var isClosed: Bool = false
14 |
15 | init(userId: String) {
16 | self.userId = userId
17 | }
18 |
19 | init(isClosed: Bool) {
20 | self.isClosed = isClosed
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_gift_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/Android/popmenu/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | version = "1.1.0"
4 |
5 | android {
6 | compileSdkVersion 29
7 |
8 | defaultConfig {
9 | minSdkVersion 14
10 | targetSdkVersion 29
11 | versionCode 110
12 | versionName version
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/MessageManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by LXH on 2019/12/11.
3 | // Copyright (c) 2019 CavanSu. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | import AgoraRtmKit
9 |
10 | protocol MessageManager {
11 | func sendOrder(userId: String, orderType: String, content: String?, callback: AgoraRtmSendPeerMessageBlock?)
12 |
13 | func sendMessage(text: String)
14 |
15 | func processMessage(rtmMessage: AgoraRtmMessage)
16 |
17 | func addMessage(message: Message)
18 | }
19 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/ChannelCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelCell.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/5.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ChannelCell: UICollectionViewCell {
12 | @IBOutlet weak var image: UIImageView!
13 | @IBOutlet weak var name: UILabel!
14 |
15 | func update(_ channel: Channel) {
16 | self.image.image = channel.drawableRes
17 | self.name.text = channel.name
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Android/app/src/test/java/io/agora/chatroom/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/manager/MessageManager.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.manager;
2 |
3 | import io.agora.chatroom.model.Message;
4 | import io.agora.rtm.ResultCallback;
5 | import io.agora.rtm.RtmMessage;
6 |
7 | public interface MessageManager {
8 |
9 | void sendOrder(String userId, String orderType, String content, ResultCallback callback);
10 |
11 | void sendMessage(String text);
12 |
13 | void processMessage(RtmMessage rtmMessage);
14 |
15 | void addMessage(Message message);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_changer_item_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Constant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constant.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/27.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct Constant {
12 | static let sUserId: UInt = UInt(UInt32(bitPattern: MemberUtil.getUserId()))
13 |
14 | static func isMyself(_ userId: String) -> Bool {
15 | userId == String(sUserId)
16 | }
17 |
18 | static let sName = MemberUtil.getName()
19 | static let sAvatarIndex = MemberUtil.getAvatarIndex()
20 | }
21 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_changer_item_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/layout_item_changer.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/manager/ChatRoomEventListener.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.manager;
2 |
3 | public interface ChatRoomEventListener {
4 |
5 | void onSeatUpdated(int position);
6 |
7 | void onUserGivingGift(String userId);
8 |
9 | void onMessageAdded(int position);
10 |
11 | void onMemberListUpdated(String userId);
12 |
13 | void onUserStatusChanged(String userId, Boolean muted);
14 |
15 | void onAudioMixingStateChanged(boolean isPlaying);
16 |
17 | void onAudioVolumeIndication(String userId, int volume);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/model/Constant.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.model;
2 |
3 | import android.text.TextUtils;
4 |
5 | import io.agora.chatroom.util.MemberUtil;
6 |
7 | public class Constant {
8 |
9 | public static final int sUserId = MemberUtil.getUserId();
10 |
11 | public static boolean isMyself(String userId) {
12 | return TextUtils.equals(userId, String.valueOf(Constant.sUserId));
13 | }
14 |
15 | public static final String sName = MemberUtil.getName();
16 | public static final int sAvatarIndex = MemberUtil.getAvatarIndex();
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by CavanSu on 2018/8/15.
6 | // Copyright © 2018 Agora. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 | var window: UIWindow?
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | RtcManager.shared.initialize()
17 | RtmManager.shared.initialize()
18 | return true
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/ChatRoomApplication.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom;
2 |
3 | import android.app.Application;
4 |
5 | import io.agora.chatroom.manager.RtcManager;
6 | import io.agora.chatroom.manager.RtmManager;
7 |
8 | public class ChatRoomApplication extends Application {
9 |
10 | public static Application instance;
11 |
12 | public ChatRoomApplication() {
13 | instance = this;
14 | }
15 |
16 | @Override
17 | public void onCreate() {
18 | super.onCreate();
19 | RtcManager.instance(this).init();
20 | RtmManager.instance(this).init();
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.3.2'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | google()
19 | jcenter()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/NavigationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationController.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/5.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class NavigationController: UINavigationController {
12 | override func viewWillAppear(_ animated: Bool) {
13 | navigationBar.setBackgroundImage(UIImage(), for: .default)
14 | navigationBar.shadowImage = UIImage()
15 | }
16 |
17 | override var preferredStatusBarStyle: UIStatusBarStyle {
18 | topViewController?.preferredStatusBarStyle ?? super.preferredStatusBarStyle
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_changer_rb_checked.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
7 |
8 |
9 |
10 |
11 |
12 | -
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_changer_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
7 |
8 |
9 |
10 |
11 |
12 | -
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/drawable/bg_changer_rb_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
7 |
8 |
9 |
10 |
11 |
12 | -
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Android/popmenu/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/model/Seat.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.model;
2 |
3 | public class Seat {
4 |
5 | private String userId;
6 | private boolean isClosed;
7 |
8 | public Seat(String userId) {
9 | this.userId = userId;
10 | }
11 |
12 | public Seat(boolean isClosed) {
13 | this.isClosed = isClosed;
14 | }
15 |
16 | public String getUserId() {
17 | return userId;
18 | }
19 |
20 | public void setUserId(String userId) {
21 | this.userId = userId;
22 | }
23 |
24 | public boolean isClosed() {
25 | return isClosed;
26 | }
27 |
28 | public void setClosed(boolean closed) {
29 | isClosed = closed;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Android/popmenu/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/felix/Workspace/Library/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/Android/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 | build/
15 |
16 | # Local configuration file (sdk path, etc)
17 | local.properties
18 |
19 | # Eclipse project files
20 | .classpath
21 | .project
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Intellij project files
27 | *.iml
28 | *.ipr
29 | *.iws
30 | .idea/
31 |
32 | # Mac OS X
33 | .DS_Store
34 |
35 | # Android Studio
36 | .gradle
37 | /local.properties
38 | /.idea/workspace.xml
39 | obj/
40 | libs/
41 |
42 | .externalNativeBuild
43 |
44 | # cscope or ctags files
45 | cscope.in.out
46 | cscope.out
47 | cscope.po.out
48 | tags
49 |
50 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #EEEEEE
4 | #EEEEEE
5 | #CCCCCC
6 | #CCCCCC
7 | #999999
8 |
9 | #333333
10 | #4C9D9C98
11 | #19FFFFFF
12 | #4CFFFFFF
13 | #66FFFFFF
14 | #99FFFFFF
15 | #09BDF4
16 | #202932
17 | #007AFF
18 |
19 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - template: cicd/templates/build-android.yml
3 | parameters:
4 | displayName: 'ChatRoomAndroid'
5 | workingDirectory: 'Android'
6 | rtcSdkUrl: 'https://download.agora.io/sdk/release/Agora_Native_SDK_for_Android_v3_1_0_VOICE.zip?_ga=2.213530388.1493357375.1597372715-269570672.1596526126'
7 | rtmSdkUrl: 'https://download.agora.io/rtmsdk/release/Agora_RTM_SDK_for_Android_v1_2_2.zip'
8 |
9 | - template: cicd/templates/build-ios.yml
10 | parameters:
11 | displayName: 'ChatRoomIos'
12 | workingDirectory: 'iOS'
13 | rtcSdkUrl: 'https://download.agora.io/sdk/release/Agora_Native_SDK_for_iOS_v3_1_0_VOICE.zip?_ga=2.52976808.1493357375.1597372715-269570672.1596526126'
14 | rtmSdkUrl: 'https://download.agora.io/rtmsdk/release/Agora_RTM_SDK_for_iOS_v1_2_2.zip'
15 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/KeyCenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by LXH on 2019/12/18.
3 | // Copyright (c) 2019 CavanSu. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | struct KeyCenter {
9 | static let AppId: String = <#Your App Id#>
10 |
11 | /* assign Token to nil if you have not enabled app certificate
12 | * before you deploy your own token server, you can easily generate a temp token for dev use
13 | * at https://dashboard.agora.io note the token generated are allowed to join corresponding room ONLY.
14 | */
15 | /* 如果没有打开鉴权Token, 这里的token值给nil就好
16 | * 生成Token需要参照官方文档部署Token服务器,开发阶段若想先不部署服务器, 可以在https://dashbaord.agora.io生成
17 | * 临时Token. 请注意生成Token时指定的频道名, 该Token只允许加入对应的频道
18 | */
19 | static let Token: String? = <#Temp Access Token#>
20 |
21 | static let RtmToken: String? = <#Temp Rtm Access Token#>
22 | }
23 |
--------------------------------------------------------------------------------
/Android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | android.useAndroidX=true
20 | android.enableJetifier=true
21 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/AttributeKey.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AttributeKey.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/11.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct AttributeKey {
12 | static let KEY_ANCHOR_ID = "anchorId"
13 | static let KEY_SEAT_ARRAY = initSeatKeys()
14 | static let KEY_USER_INFO = "userInfo"
15 |
16 | private static func initSeatKeys() -> [String] {
17 | var strings = [String]()
18 | for i in 0.. Int {
25 | for (i, item) in KEY_SEAT_ARRAY.enumerated() {
26 | if key == item {
27 | return i
28 | }
29 | }
30 | return NSNotFound
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Android/app/src/androidTest/java/io/agora/chatroom/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.InstrumentationRegistry;
6 | import androidx.test.runner.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.assertEquals;
12 |
13 | /**
14 | * Instrumentation test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() throws Exception {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getTargetContext();
24 |
25 | assertEquals("io.agora.chatroom", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/model/AttributeKey.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.model;
2 |
3 | import android.text.TextUtils;
4 |
5 | import java.util.Locale;
6 |
7 | public class AttributeKey {
8 | public static final String KEY_ANCHOR_ID = "anchorId";
9 | public static final String[] KEY_SEAT_ARRAY = initSeatKeys();
10 | public static final String KEY_USER_INFO = "userInfo";
11 |
12 | private static String[] initSeatKeys() {
13 | String[] strings = new String[ChannelData.MAX_SEAT_NUM];
14 | for (int i = 0; i < strings.length; i++) {
15 | strings[i] = String.format(Locale.getDefault(), "seat%d", i);
16 | }
17 | return strings;
18 | }
19 |
20 | public static int indexOfSeatKey(String key) {
21 | for (int i = 0; i < KEY_SEAT_ARRAY.length; i++) {
22 | if (TextUtils.equals(key, KEY_SEAT_ARRAY[i])) return i;
23 | }
24 | return -1;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/VoiceChangerCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VoiceChangerCell.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/27.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class VoiceChangerCell: UICollectionViewCell {
12 | @IBOutlet weak var effect: UIButton!
13 |
14 | func update(_ isEffect: Bool, _ effectSelectedIndex: Int, _ beautifySelectedIndex: Int, _ position: Int) {
15 | var name: String
16 | var selectedIndex: Int
17 | if isEffect {
18 | name = VoiceEffect.allCases[position].description()
19 | selectedIndex = effectSelectedIndex
20 | } else {
21 | name = VoiceBeautify.allCases[position].description()
22 | selectedIndex = beautifySelectedIndex
23 | }
24 | effect.setTitle(name, for: .normal)
25 | effect.borderColor = position == selectedIndex ? #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1) : #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.6)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/values/strings_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <#Your App Id#>
8 |
9 |
10 |
11 | <#Temp Access Token#>
12 |
13 |
14 |
15 | <#Temp Rtm Access Token#>
16 |
17 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/zh-Hans.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UITextField"; placeholder = "说点什么..."; ObjectID = "5Pp-tn-Ieq"; */
3 | "5Pp-tn-Ieq.placeholder" = "说点什么...";
4 |
5 | /* Class = "UINavigationItem"; title = "房间列表"; ObjectID = "Fe3-uR-aXQ"; */
6 | "Fe3-uR-aXQ.title" = "房间列表";
7 |
8 | /* Class = "UIButton"; normalTitle = "变声"; ObjectID = "MlU-WI-fjV"; */
9 | "MlU-WI-fjV.normalTitle" = "变声";
10 |
11 | /* Class = "UILabel"; text = "向主播赠送了礼物"; ObjectID = "QhM-zl-GUN"; */
12 | "QhM-zl-GUN.text" = "向主播赠送了礼物";
13 |
14 | /* Class = "UIButton"; normalTitle = "音效"; ObjectID = "eoi-KU-MBF"; */
15 | "eoi-KU-MBF.normalTitle" = "音效";
16 |
17 | /* Class = "UIButton"; normalTitle = "伴奏"; ObjectID = "jMg-Wz-Zfe"; */
18 | "jMg-Wz-Zfe.normalTitle" = "伴奏";
19 |
20 | /* Class = "UINavigationItem"; title = "语聊房"; ObjectID = "lqB-1a-WGr"; */
21 | "lqB-1a-WGr.title" = "语聊房";
22 |
23 | /* Class = "UIButton"; normalTitle = "0"; ObjectID = "q2g-NQ-eEd"; */
24 | "q2g-NQ-eEd.normalTitle" = "0";
25 |
26 | /* Class = "UIButton"; normalTitle = "美声"; ObjectID = "uSM-uv-z2i"; */
27 | "uSM-uv-z2i.normalTitle" = "美声";
28 |
--------------------------------------------------------------------------------
/Android/popmenu/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/widget/FixedRatioImageView.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 |
6 | import androidx.annotation.Nullable;
7 | import androidx.appcompat.widget.AppCompatImageView;
8 |
9 | public class FixedRatioImageView extends AppCompatImageView {
10 |
11 | private static final float ITEM_BG_RATIO = 141 / (float) 160;
12 |
13 | public FixedRatioImageView(Context context) {
14 | super(context);
15 | }
16 |
17 | public FixedRatioImageView(Context context, @Nullable AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 |
21 | public FixedRatioImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
22 | super(context, attrs, defStyleAttr);
23 | }
24 |
25 | @Override
26 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
27 | int width = getMeasuredWidth();
28 | int height = (int) (width * ITEM_BG_RATIO);
29 | setMeasuredDimension(widthMeasureSpec, height);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Android/popmenu/src/main/java/me/kareluo/ui/OptionItemView.java:
--------------------------------------------------------------------------------
1 | package me.kareluo.ui;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.Gravity;
6 | import android.widget.CheckedTextView;
7 |
8 | /**
9 | * Created by felix on 16/11/21.
10 | */
11 | public class OptionItemView extends CheckedTextView {
12 |
13 | public OptionItemView(Context context) {
14 | this(context, null, 0);
15 | }
16 |
17 | public OptionItemView(Context context, AttributeSet attrs) {
18 | this(context, attrs, 0);
19 | }
20 |
21 | public OptionItemView(Context context, AttributeSet attrs, int defStyleAttr) {
22 | super(context, attrs, defStyleAttr);
23 | initialize(context, attrs, defStyleAttr);
24 | }
25 |
26 | public OptionItemView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
27 | super(context, attrs, defStyleAttr);
28 | initialize(context, attrs, defStyleAttr);
29 | }
30 |
31 | private void initialize(Context context, AttributeSet attrs, int defStyleAttr) {
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/model/Channel.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.model;
2 |
3 | import androidx.annotation.DrawableRes;
4 |
5 | public class Channel {
6 |
7 | private int drawableRes;
8 | private int backgroundRes;
9 | private String name;
10 |
11 | public Channel(@DrawableRes int drawableRes, @DrawableRes int backgroundRes, String name) {
12 | this.drawableRes = drawableRes;
13 | this.backgroundRes = backgroundRes;
14 | this.name = name;
15 | }
16 |
17 | public int getDrawableRes() {
18 | return drawableRes;
19 | }
20 |
21 | public void setDrawableRes(@DrawableRes int drawableRes) {
22 | this.drawableRes = drawableRes;
23 | }
24 |
25 | public int getBackgroundRes() {
26 | return backgroundRes;
27 | }
28 |
29 | public void setBackgroundRes(@DrawableRes int backgroundRes) {
30 | this.backgroundRes = backgroundRes;
31 | }
32 |
33 | public String getName() {
34 | return name;
35 | }
36 |
37 | public void setName(String name) {
38 | this.name = name;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/MessageCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageCell.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/22.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MessageCell: UITableViewCell {
12 | @IBOutlet weak var avatar: UIImageView!
13 | @IBOutlet weak var message: UILabel!
14 |
15 | func update(_ channelData: ChannelData, _ position: Int) {
16 | let message = channelData.getMessageArray()[position]
17 | let userId = message.sendId
18 |
19 | avatar.image = channelData.getMemberAvatar(userId)
20 |
21 | switch message.messageType {
22 | case Message.MESSAGE_TYPE_TEXT:
23 | self.message.isHidden = false
24 | if let member = channelData.getMember(userId), let name = member.name {
25 | self.message.text = "\(name):\(message.content!)"
26 | } else {
27 | self.message.text = "\(userId):\(message.content!)"
28 | }
29 | case Message.MESSAGE_TYPE_IMAGE:
30 | // TODO
31 | break
32 | default:
33 | break
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/layout_item_channel.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Android/popmenu/src/main/java/me/kareluo/ui/PopVerticalScrollView.java:
--------------------------------------------------------------------------------
1 | package me.kareluo.ui;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.widget.ScrollView;
7 |
8 | import me.kareluo.ui.PopLayout.OnBulgeChangeCallback;
9 |
10 | /**
11 | * Created by felix on 17/1/10.
12 | */
13 | public class PopVerticalScrollView extends ScrollView implements OnBulgeChangeCallback {
14 |
15 | public PopVerticalScrollView(Context context) {
16 | super(context);
17 | }
18 |
19 | public PopVerticalScrollView(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | }
22 |
23 | public PopVerticalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
24 | super(context, attrs, defStyleAttr);
25 | }
26 |
27 | @Override
28 | public void onBulgeChanged(int site, int size) {
29 | if (getChildCount() > 0) {
30 | View view = getChildAt(0);
31 | if (view instanceof OnBulgeChangeCallback) {
32 | ((OnBulgeChangeCallback) view).onBulgeChanged(site, size);
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Member.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Member.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/25.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct Member: Codable {
12 | var userId: String
13 | var name: String?
14 | var avatarIndex: Int?
15 |
16 | init(userId: String) {
17 | self.userId = userId
18 | }
19 |
20 | init(userId: String, name: String, avatarIndex: Int) {
21 | self.init(userId: userId)
22 | self.name = name
23 | self.avatarIndex = avatarIndex
24 | }
25 |
26 | mutating func update(_ member: Member) {
27 | self.name = member.name
28 | self.avatarIndex = member.avatarIndex
29 | }
30 |
31 | func toJsonString() -> String? {
32 | if let data = try? JSONEncoder().encode(self) {
33 | return String(data: data, encoding: .utf8)
34 | }
35 | return nil
36 | }
37 |
38 | static func fromJsonString(_ str: String) -> Member? {
39 | if let data = str.data(using: .utf8) {
40 | return try? JSONDecoder().decode(Member.self, from: data)
41 | }
42 | return nil
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Android/popmenu/src/main/java/me/kareluo/ui/PopHorizontalScrollView.java:
--------------------------------------------------------------------------------
1 | package me.kareluo.ui;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.widget.HorizontalScrollView;
7 |
8 | import me.kareluo.ui.PopLayout.OnBulgeChangeCallback;
9 |
10 | /**
11 | * Created by felix on 17/1/10.
12 | */
13 | public class PopHorizontalScrollView extends HorizontalScrollView implements OnBulgeChangeCallback {
14 |
15 | public PopHorizontalScrollView(Context context) {
16 | super(context);
17 | }
18 |
19 | public PopHorizontalScrollView(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | }
22 |
23 | public PopHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
24 | super(context, attrs, defStyleAttr);
25 | }
26 |
27 | @Override
28 | public void onBulgeChanged(int site, int size) {
29 | if (getChildCount() > 0) {
30 | View view = getChildAt(0);
31 | if (view instanceof OnBulgeChangeCallback) {
32 | ((OnBulgeChangeCallback) view).onBulgeChanged(site, size);
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/CustomView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomView.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/16.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIView {
12 | @IBInspectable var cornerRadius: CGFloat {
13 | get {
14 | layer.cornerRadius
15 | }
16 |
17 | set {
18 | layer.cornerRadius = newValue
19 | layer.masksToBounds = newValue > 0
20 | }
21 | }
22 |
23 | @IBInspectable var borderWidth: CGFloat {
24 | get {
25 | layer.borderWidth
26 | }
27 | set {
28 | layer.borderWidth = newValue > 0 ? newValue : 0
29 | }
30 | }
31 |
32 | @IBInspectable var borderColor: UIColor {
33 | get {
34 | UIColor(cgColor: layer.borderColor!)
35 | }
36 | set {
37 | layer.borderColor = newValue.cgColor
38 | }
39 | }
40 | }
41 |
42 | extension UITextField {
43 | @IBInspectable var placeholderColor: UIColor {
44 | get {
45 | value(forKeyPath: "_placeholderLabel.textColor") as! UIColor
46 | }
47 | set {
48 | setValue(newValue, forKeyPath: "_placeholderLabel.textColor")
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/MessageTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageTableViewController.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/22.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import AgoraRtmKit
12 |
13 | class MessageTableViewController: UITableViewController {
14 | private var mChannelData = ChatRoomManager.shared.getChannelData()
15 |
16 | func insertRows(_ position: Int) {
17 | let indexPath = IndexPath(row: position, section: 0)
18 | tableView.insertRows(at: [indexPath], with: .none)
19 | tableView.scrollToRow(at: indexPath, at: .none, animated: true)
20 | }
21 | }
22 |
23 | extension MessageTableViewController {
24 | // MARK: - UITableViewDataSource
25 |
26 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
27 | mChannelData.getMessageArray().count
28 | }
29 |
30 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> MessageCell {
31 | let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath) as! MessageCell
32 |
33 | cell.selectionStyle = .none
34 | cell.update(mChannelData, indexPath.row)
35 |
36 | return cell
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/activity_channel_grid.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
19 |
20 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | AgoraChatRoom
4 |
5 | Created by LXH on 2019/12/18.
6 | Copyright © 2019 CavanSu. All rights reserved.
7 | */
8 |
9 | "Zhao" = "赵";
10 | "Qian" = "钱";
11 | "Sun" = "孙";
12 | "Li" = "李";
13 | "Zhou" = "周";
14 | "Wu" = "吴";
15 | "Zheng" = "郑";
16 | "Wang" = "王";
17 | "Feng" = "冯";
18 | "Chen" = "陈";
19 | "Chu" = "褚";
20 | "Wei" = "卫";
21 |
22 | "Fuqiang" = "富强";
23 | "Minzhu" = "民主";
24 | "Wenming" = "文明";
25 | "Hexie" = "和谐";
26 | "Ziyou" = "自由";
27 | "Pingdeng" = "平等";
28 | "Gongzheng" = "公正";
29 | "Fazhi" = "法治";
30 | "Aiguo" = "爱国";
31 | "Jingye" = "敬业";
32 | "Chengxin" = "诚信";
33 | "Youshan" = "友善";
34 |
35 | "KTV" = "KTV";
36 | "Live" = "演唱会";
37 | "Uncle" = "大叔";
38 | "Girl" = "小姐姐";
39 | "Studio" = "录音棚";
40 | "Pop" = "流行";
41 | "R&B" = "R&B";
42 | "Phonograph" = "留声机";
43 |
44 | "Default" = "原声";
45 | "Thick" = "浑厚";
46 | "Low" = "低沉";
47 | "Round" = "圆润";
48 | "Falsetto" = "假音";
49 | "Full" = "饱满";
50 | "Clear" = "清澈";
51 | "Resounding" = "高亢";
52 | "Loud" = "嘹亮";
53 | "OpenAir" = "空旷";
54 |
55 | "to_broadcast" = "上麦";
56 | "to_audience" = "下麦";
57 | "channel_member_list" = "房间成员列表";
58 | "people" = "人";
59 | "turn_off_mic" = "禁麦";
60 | "turn_on_mic" = "解麦";
61 | "open_seat" = "解封";
62 | "close_seat" = "封麦";
63 | "anchor" = "(主播)";
64 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/layout_item_seat.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
20 |
21 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/cicd/templates/build-android.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | displayName: ''
3 | workingDirectory: ''
4 | rtcSdkUrl: ''
5 | rtmSdkUrl: ''
6 |
7 | jobs:
8 | - job: ${{ parameters.displayName }}_Build
9 | displayName: ${{ parameters.displayName }}
10 |
11 | pool:
12 | vmImage: 'macOS-latest'
13 |
14 | variables:
15 | - group: AgoraKeys
16 |
17 | steps:
18 | - script: cd ${{ parameters.workingDirectory }} && ls && python ci.env.py
19 | env:
20 | RTC_SDK_URL: ${{ parameters.rtcSdkUrl }}
21 | RTM_SDK_URL: ${{ parameters.rtmSdkUrl }}
22 | AGORA_APP_ID: $(agora.appId)
23 |
24 | - script: ls ${{ parameters.workingDirectory }}/app/libs
25 |
26 | - task: Gradle@2
27 | inputs:
28 | gradleWrapperFile: ${{ parameters.workingDirectory }}/gradlew
29 | workingDirectory: ${{ parameters.workingDirectory }}
30 | tasks: 'assembleDebug'
31 | publishJUnitResults: false
32 | gradleOptions: '-Xmx3072m'
33 |
34 | - task: CopyFiles@2
35 | inputs:
36 | contents: '**/*.apk'
37 | targetFolder: '$(build.artifactStagingDirectory)'
38 |
39 | - task: PublishBuildArtifacts@1
40 | inputs:
41 | pathtoPublish: '$(build.artifactStagingDirectory)'
42 | artifactName: ${{ parameters.displayName }}
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | AgoraChatRoom
4 |
5 | Created by LXH on 2019/12/18.
6 | Copyright © 2019 CavanSu. All rights reserved.
7 | */
8 |
9 | "Zhao" = "Zhao";
10 | "Qian" = "Qian";
11 | "Sun" = "Sun";
12 | "Li" = "Li";
13 | "Zhou" = "Zhou";
14 | "Wu" = "Wu";
15 | "Zheng" = "Zheng";
16 | "Wang" = "Wang";
17 | "Feng" = "Feng";
18 | "Chen" = "Chen";
19 | "Chu" = "Chu";
20 | "Wei" = "Wei";
21 |
22 | "Fuqiang" = "Fuqiang";
23 | "Minzhu" = "Minzhu";
24 | "Wenming" = "WenMing";
25 | "Hexie" = "Hexie";
26 | "Ziyou" = "Ziyou";
27 | "Pingdeng" = "Pingdeng";
28 | "Gongzheng" = "Gongzheng";
29 | "Fazhi" = "Fazhi";
30 | "Aiguo" = "Aiguo";
31 | "Jingye" = "Jingye";
32 | "Chengxin" = "Chengxin";
33 | "Youshan" = "Youshan";
34 |
35 | "KTV" = "KTV";
36 | "Live" = "Live";
37 | "Uncle" = "Uncle";
38 | "Girl" = "Girl";
39 | "Studio" = "Studio";
40 | "Pop" = "Pop";
41 | "R&B" = "R&B";
42 | "Phonograph" = "Phonograph";
43 |
44 | "Default" = "Default";
45 | "Thick" = "Thick";
46 | "Low" = "Low";
47 | "Round" = "Round";
48 | "Falsetto" = "Falsetto";
49 | "Full" = "Full";
50 | "Clear" = "Clear";
51 | "Resounding" = "Resounding";
52 | "Loud" = "Loud";
53 | "OpenAir" = "OpenAir";
54 |
55 | "to_broadcast" = "toBroadcast";
56 | "to_audience" = "toAudience";
57 | "channel_member_list" = "Channel member list";
58 | "people" = "people";
59 | "turn_off_mic" = "Turn off mic";
60 | "turn_on_mic" = "Turn on mic";
61 | "open_seat" = "Open";
62 | "close_seat" = "Close";
63 | "anchor" = "(Anchor)";
64 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/AlertUtil.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertUtil.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/26.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct AlertUtil {
12 | static func showAlert(_ root: UIViewController, _ text: String) {
13 | let vc = UIAlertController(title: nil, message: text, preferredStyle: .alert)
14 | vc.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
15 | root.present(vc, animated: true, completion: nil)
16 | }
17 |
18 | static func showMenu(_ root: UIView, _ selectors: [Selector]) {
19 | root.becomeFirstResponder()
20 | let menu = UIMenuController.shared
21 | menu.menuItems = [
22 | UIMenuItem(title: NSLocalizedString("to_broadcast", comment: ""), action: selectors[0]),
23 | UIMenuItem(title: NSLocalizedString("to_audience", comment: ""), action: selectors[1]),
24 | UIMenuItem(title: NSLocalizedString("turn_off_mic", comment: ""), action: selectors[2]),
25 | UIMenuItem(title: NSLocalizedString("turn_on_mic", comment: ""), action: selectors[3]),
26 | UIMenuItem(title: NSLocalizedString("close_seat", comment: ""), action: selectors[4]),
27 | UIMenuItem(title: NSLocalizedString("open_seat", comment: ""), action: selectors[5])
28 | ]
29 | menu.arrowDirection = .up
30 | menu.setTargetRect(root.frame, in: root.superview!)
31 | menu.setMenuVisible(true, animated: true)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/layout_item_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
24 |
25 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | defaultConfig {
6 | applicationId "io.agora.chatroom"
7 | minSdkVersion 17
8 | targetSdkVersion 29
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | compileOptions {
20 | sourceCompatibility JavaVersion.VERSION_1_8
21 | targetCompatibility JavaVersion.VERSION_1_8
22 | }
23 | sourceSets {
24 | main {
25 | jniLibs.srcDirs = ['libs']
26 | }
27 | }
28 | }
29 |
30 | dependencies {
31 | implementation fileTree(dir: 'libs', include: ['*.jar'])
32 | implementation project(':popmenu')
33 |
34 | implementation 'androidx.appcompat:appcompat:1.1.0'
35 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
36 | implementation 'androidx.recyclerview:recyclerview:1.1.0'
37 | implementation "com.google.code.gson:gson:2.8.5"
38 | implementation 'de.hdodenhof:circleimageview:3.0.0'
39 |
40 | implementation 'com.jakewharton:butterknife:10.2.0'
41 | annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.0'
42 |
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
44 | testImplementation 'junit:junit:4.12'
45 | }
46 |
--------------------------------------------------------------------------------
/Android/ci.env.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: UTF-8 -*-
3 | import re
4 | import os
5 | import shutil
6 |
7 | TARGET_LIBS_ZIP = "agora_sdk.zip"
8 | TARGET_INTERNAL_FOLDER = "agora_sdk"
9 |
10 |
11 | def main():
12 | RTC_SDK_URL = ""
13 | if "RTC_SDK_URL" in os.environ:
14 | RTC_SDK_URL = os.environ["RTC_SDK_URL"]
15 |
16 | RTM_SDK_URL = ""
17 | if "RTM_SDK_URL" in os.environ:
18 | RTM_SDK_URL = os.environ["RTM_SDK_URL"]
19 |
20 | downloadSDK(RTC_SDK_URL)
21 | downloadSDK(RTM_SDK_URL)
22 |
23 | if not os.path.exists("app/libs"):
24 | os.mkdir("app/libs")
25 |
26 | mv = "cp -f -r " + TARGET_INTERNAL_FOLDER + "/*/libs/* app/libs"
27 | os.system(mv)
28 |
29 | os.remove(TARGET_LIBS_ZIP)
30 | shutil.rmtree(TARGET_INTERNAL_FOLDER, ignore_errors=True)
31 |
32 | appId = ""
33 | if "AGORA_APP_ID" in os.environ:
34 | appId = os.environ["AGORA_APP_ID"]
35 | token = ""
36 |
37 | # if need reset
38 | f = open("./app/src/main/res/values/strings_config.xml", 'r+')
39 | content = f.read()
40 |
41 | # if need reset
42 | contentNew = re.sub(r'<#Your App Id#>', appId, content)
43 | contentNew = re.sub(r'<#Temp Access Token#>', token, contentNew)
44 | contentNew = re.sub(r'<#Temp Rtm Access Token#>', token, contentNew)
45 |
46 | f.seek(0)
47 | f.write(contentNew)
48 | f.truncate()
49 |
50 |
51 | def downloadSDK(url):
52 | wget = "wget " + url + " -O " + TARGET_LIBS_ZIP
53 | os.system(wget)
54 |
55 | unzip = "unzip " + TARGET_LIBS_ZIP + " \"*/libs/*\" -d " + TARGET_INTERNAL_FOLDER
56 | os.system(unzip)
57 |
58 |
59 | if __name__ == "__main__":
60 | main()
61 |
--------------------------------------------------------------------------------
/Android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Message.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Message.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/25.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct Message: Codable {
12 | static let MESSAGE_TYPE_TEXT = 0
13 | static let MESSAGE_TYPE_IMAGE = 1
14 | static let MESSAGE_TYPE_GIFT = 2
15 | static let MESSAGE_TYPE_ORDER = 3
16 |
17 | static let ORDER_TYPE_AUDIENCE = "toAudience"
18 | static let ORDER_TYPE_BROADCASTER = "toBroadcaster"
19 | static let ORDER_TYPE_MUTE = "mute"
20 |
21 | var messageType: Int = Message.MESSAGE_TYPE_TEXT
22 | var orderType: String?
23 | var content: String?
24 | var sendId: String
25 |
26 | init(content: String?, sendId: UInt) {
27 | self.content = content
28 | self.sendId = String(sendId)
29 | }
30 |
31 | init(messageType: Int, content: String?, sendId: UInt) {
32 | self.init(content: content, sendId: sendId)
33 | self.messageType = messageType
34 | }
35 |
36 | init(orderType: String, content: String?, sendId: UInt) {
37 | self.init(content: content, sendId: sendId)
38 | self.messageType = Message.MESSAGE_TYPE_ORDER
39 | self.orderType = orderType
40 | }
41 |
42 | func toJsonString() -> String? {
43 | if let data = try? JSONEncoder().encode(self) {
44 | return String(data: data, encoding: .utf8)
45 | }
46 | return nil
47 | }
48 |
49 | static func fromJsonString(_ str: String) -> Message? {
50 | if let data = str.data(using: .utf8) {
51 | return try? JSONDecoder().decode(Message.self, from: data)
52 | }
53 | return nil
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/model/Member.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.model;
2 |
3 | import android.text.TextUtils;
4 |
5 | import androidx.annotation.Nullable;
6 |
7 | import com.google.gson.Gson;
8 |
9 | public class Member {
10 |
11 | private String userId;
12 | private String name;
13 | private int avatarIndex;
14 |
15 | public Member(String userId) {
16 | this.userId = userId;
17 | }
18 |
19 | public Member(String userId, String name, int avatarIndex) {
20 | this(userId);
21 | this.name = name;
22 | this.avatarIndex = avatarIndex;
23 | }
24 |
25 | public String getUserId() {
26 | return userId;
27 | }
28 |
29 | public void setUserId(String userId) {
30 | this.userId = userId;
31 | }
32 |
33 | public String getName() {
34 | return name;
35 | }
36 |
37 | public void setName(String name) {
38 | this.name = name;
39 | }
40 |
41 | public int getAvatarIndex() {
42 | return avatarIndex;
43 | }
44 |
45 | public void setAvatarIndex(int avatarIndex) {
46 | this.avatarIndex = avatarIndex;
47 | }
48 |
49 | public void update(Member member) {
50 | this.name = member.name;
51 | this.avatarIndex = member.avatarIndex;
52 | }
53 |
54 | @Override
55 | public boolean equals(@Nullable Object obj) {
56 | if (obj instanceof Member)
57 | return TextUtils.equals(userId, ((Member) obj).userId);
58 | return super.equals(obj);
59 | }
60 |
61 | public String toJsonString() {
62 | return new Gson().toJson(this);
63 | }
64 |
65 | public static Member fromJsonString(String str) {
66 | return new Gson().fromJson(str, Member.class);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/zh-Hans.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | ChatRoom
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSMicrophoneUsageDescription
26 | ChatRoom need mic
27 | UIBackgroundModes
28 |
29 | audio
30 |
31 | UILaunchStoryboardName
32 | LaunchScreen
33 | UIMainStoryboardFile
34 | Main
35 | UIRequiredDeviceCapabilities
36 |
37 | armv7
38 |
39 | UIStatusBarStyle
40 | UIStatusBarStyleLightContent
41 | UISupportedInterfaceOrientations
42 |
43 | UIInterfaceOrientationPortrait
44 |
45 | UISupportedInterfaceOrientations~ipad
46 |
47 | UIInterfaceOrientationPortrait
48 | UIInterfaceOrientationPortraitUpsideDown
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/GiftPopView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GiftPopView.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/16.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class GiftPopView: UIView {
12 | @IBOutlet weak var avatar: UIImageView!
13 | @IBOutlet weak var name: UILabel!
14 |
15 | func show(_ userId: String) {
16 | let channelData = ChatRoomManager.shared.getChannelData()
17 | if let member = channelData.getMember(userId) {
18 | name.text = member.name
19 | } else {
20 | name.text = userId
21 | }
22 | avatar.image = channelData.getMemberAvatar(userId)
23 |
24 | isHidden = false
25 | groupAnimation()
26 | perform(#selector(hide), with: nil, afterDelay: 2.5)
27 | }
28 |
29 | func groupAnimation() {
30 | let animation = CAAnimationGroup()
31 | animation.animations = [positionAnimation(), opacityAnimation()]
32 | animation.duration = 1
33 | layer.add(animation, forKey: "groupAnimation")
34 | }
35 |
36 | func positionAnimation() -> CABasicAnimation {
37 | let size = UIApplication.shared.windows[0].bounds.size
38 | let animation = CABasicAnimation.init(keyPath: "position")
39 | animation.fromValue = CGPoint.init(x: size.width / 2, y: size.height / 2 + self.frame.size.height)
40 | animation.toValue = CGPoint.init(x: size.width / 2, y: size.height / 2)
41 | return animation
42 | }
43 |
44 | func opacityAnimation() -> CABasicAnimation {
45 | let animation = CABasicAnimation.init(keyPath: "opacity")
46 | animation.fromValue = NSNumber.init(value: 0)
47 | animation.toValue = NSNumber.init(value: 1)
48 | return animation
49 | }
50 |
51 | @objc private func hide() {
52 | isHidden = true
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/iOS/ci.env.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: UTF-8 -*-
3 | import re
4 | import os
5 | import shutil
6 |
7 | TARGET_LIBS_ZIP = "agora_sdk.zip"
8 | TARGET_INTERNAL_FOLDER = "agora_sdk"
9 |
10 |
11 | def main():
12 | RTC_SDK_URL = ""
13 | if "RTC_SDK_URL" in os.environ:
14 | RTC_SDK_URL = os.environ["RTC_SDK_URL"]
15 |
16 | RTM_SDK_URL = ""
17 | if "RTM_SDK_URL" in os.environ:
18 | RTM_SDK_URL = os.environ["RTM_SDK_URL"]
19 |
20 | SCHEME = ""
21 | if "SCHEME" in os.environ:
22 | SCHEME = os.environ["SCHEME"]
23 |
24 | downloadSDK(RTC_SDK_URL)
25 | downloadSDK(RTM_SDK_URL)
26 |
27 | if not os.path.exists(SCHEME + "/libs"):
28 | os.mkdir(SCHEME + "/libs")
29 |
30 | mv = "cp -f -r " + TARGET_INTERNAL_FOLDER + "/*/libs/* " + SCHEME + "/libs"
31 | os.system(mv)
32 |
33 | os.remove(TARGET_LIBS_ZIP)
34 | shutil.rmtree(TARGET_INTERNAL_FOLDER, ignore_errors=True)
35 |
36 | appId = ""
37 | if "AGORA_APP_ID" in os.environ:
38 | appId = os.environ["AGORA_APP_ID"]
39 | token = ""
40 |
41 | # if need reset
42 | f = open("./" + SCHEME + "/KeyCenter.swift", 'r+')
43 | content = f.read()
44 |
45 | # if need reset
46 | agoraAppString = "\"" + appId + "\""
47 | agoraTokenString = "\"" + token + "\""
48 | contentNew = re.sub(r'<#Your App Id#>', agoraAppString, content)
49 | contentNew = re.sub(r'<#Temp Access Token#>', agoraTokenString, contentNew)
50 | contentNew = re.sub(r'<#Temp Rtm Access Token#>', agoraTokenString, contentNew)
51 |
52 | f.seek(0)
53 | f.write(contentNew)
54 | f.truncate()
55 |
56 |
57 | def downloadSDK(url):
58 | wget = "wget " + url + " -O " + TARGET_LIBS_ZIP
59 | os.system(wget)
60 |
61 | unzip = "unzip " + TARGET_LIBS_ZIP + " \"*/libs/*\" -d " + TARGET_INTERNAL_FOLDER
62 | os.system(unzip)
63 |
64 |
65 | if __name__ == "__main__":
66 | main()
67 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/MemberCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemberCell.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/26.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MemberCell: UITableViewCell {
12 | @IBOutlet weak var avatar: UIImageView!
13 | @IBOutlet weak var ivMute: UIImageView!
14 | @IBOutlet weak var name: UILabel!
15 | @IBOutlet weak var role: UIButton!
16 | @IBOutlet weak var btnMute: UIButton!
17 |
18 | func update(_ channelData: ChannelData, _ position: Int) {
19 | let member = channelData.getMemberArray()[position]
20 | let userId = member.userId
21 |
22 | self.avatar.image = channelData.getMemberAvatar(userId)
23 |
24 | if channelData.isUserOnline(userId) {
25 | let muted = channelData.isUserMuted(userId)
26 | self.ivMute.isHidden = false
27 | self.ivMute.image = muted ? #imageLiteral(resourceName: "ic_mic_off_little") : #imageLiteral(resourceName: "ic_mic_on_little")
28 | self.role.setTitle(NSLocalizedString("to_audience", comment: ""), for: .normal)
29 | self.btnMute.isHidden = false
30 | self.btnMute.setTitle(muted ? NSLocalizedString("turn_on_mic", comment: "") : NSLocalizedString("turn_off_mic", comment: ""), for: .normal)
31 | } else {
32 | self.ivMute.isHidden = true
33 | self.role.setTitle(NSLocalizedString("to_broadcast", comment: ""), for: .normal)
34 | self.btnMute.isHidden = true
35 | }
36 |
37 | if !channelData.isAnchorMyself() {
38 | self.role.isHidden = true
39 | self.btnMute.isHidden = true
40 | }
41 |
42 | var name = member.name
43 | if channelData.isAnchor(userId) {
44 | name = "\(name ?? userId)\(NSLocalizedString("anchor", comment: ""))"
45 | }
46 | self.name.text = name
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/dialog_member_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
30 |
31 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/SeatCollectionViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SeatCollectionViewController.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/22.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SeatCollectionViewController: UICollectionViewController {
12 | private var mChannelData = ChatRoomManager.shared.getChannelData()
13 |
14 | func reloadItems(_ position: Int) {
15 | collectionView.reloadItems(at: [IndexPath(row: position, section: 0)])
16 | }
17 |
18 | func reloadItems(_ userId: String?) {
19 | if let `userId` = userId {
20 | let index = mChannelData.indexOfSeatArray(userId)
21 | if index != NSNotFound {
22 | collectionView.reloadItems(at: [IndexPath(row: index, section: 0)])
23 | }
24 | }
25 | }
26 | }
27 |
28 | extension SeatCollectionViewController {
29 | // MARK: - UICollectionViewDataSource
30 |
31 | override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
32 | mChannelData.getSeatArray().count
33 | }
34 |
35 | override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> SeatCell {
36 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SeatCell", for: indexPath) as! SeatCell
37 |
38 | cell.update(mChannelData, indexPath.item)
39 | cell.seat.layoutIfNeeded()
40 | cell.seat.cornerRadius = cell.seat.frame.size.height / 2
41 |
42 | return cell
43 | }
44 | }
45 |
46 | extension SeatCollectionViewController: UICollectionViewDelegateFlowLayout {
47 | // MARK: - UICollectionViewDelegateFlowLayout
48 |
49 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
50 | let width = UIApplication.shared.windows[0].bounds.size.width
51 | let size = Int((width - 10 * 2 * 5) / 5)
52 | return CGSize.init(width: size, height: size)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/cicd/templates/build-ios.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | displayName: ''
3 | workingDirectory: ''
4 | rtcSdkUrl: ''
5 | rtmSdkUrl: ''
6 | scheme: 'AgoraChatRoom'
7 |
8 | jobs:
9 | - job: ${{ parameters.displayName }}_Build
10 | displayName: ${{ parameters.displayName }}
11 |
12 | pool:
13 | vmImage: 'macOS-latest'
14 |
15 | variables:
16 | - group: AgoraKeys
17 | - name: configuration
18 | value: 'Release'
19 | - name: sdk
20 | value: 'iphoneos'
21 |
22 | steps:
23 | - script: cd ${{ parameters.workingDirectory }} && ls && python ci.env.py
24 | env:
25 | RTC_SDK_URL: ${{ parameters.rtcSdkUrl }}
26 | RTM_SDK_URL: ${{ parameters.rtmSdkUrl }}
27 | SCHEME: ${{ parameters.scheme }}
28 | AGORA_APP_ID: '$(agora.appId)'
29 |
30 | - script: ls ${{ parameters.workingDirectory }}/${{ parameters.scheme }}/libs
31 |
32 | - task: InstallAppleCertificate@2
33 | inputs:
34 | certSecureFile: 'certificate.p12'
35 | certPwd: '$(agora.password)'
36 |
37 | - task: InstallAppleProvisioningProfile@1
38 | inputs:
39 | provProfileSecureFile: 'AgoraAppsDevProfile.mobileprovision'
40 |
41 | - task: Xcode@5
42 | inputs:
43 | actions: 'build'
44 | configuration: '$(configuration)'
45 | sdk: '$(sdk)'
46 | xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
47 | scheme: ${{ parameters.scheme }}
48 | packageApp: 'true'
49 | exportMethod: 'development'
50 | signingOption: 'manual'
51 | signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)'
52 | provisioningProfileUuid: '$(APPLE_PROV_PROFILE_UUID)'
53 | useXcpretty: 'false'
54 |
55 | - task: CopyFiles@2
56 | inputs:
57 | contents: '**/*.ipa'
58 | targetFolder: '$(build.artifactStagingDirectory)'
59 |
60 | - task: PublishBuildArtifacts@1
61 | inputs:
62 | pathtoPublish: '$(build.artifactStagingDirectory)'
63 | artifactName: ${{ parameters.displayName }}
--------------------------------------------------------------------------------
/Android/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 001
5 | - 002
6 | - 003
7 | - 004
8 | - 005
9 |
10 |
11 |
12 | - @mipmap/img_channel_0
13 | - @mipmap/img_channel_1
14 | - @mipmap/img_channel_2
15 | - @mipmap/img_channel_3
16 | - @mipmap/img_channel_4
17 |
18 |
19 |
20 | - @mipmap/bg_channel_0
21 | - @mipmap/bg_channel_1
22 | - @mipmap/bg_channel_2
23 | - @mipmap/bg_channel_3
24 | - @mipmap/bg_channel_4
25 |
26 |
27 |
28 | - @mipmap/img_avatar_0
29 | - @mipmap/img_avatar_1
30 | - @mipmap/img_avatar_2
31 | - @mipmap/img_avatar_3
32 | - @mipmap/img_avatar_4
33 | - @mipmap/img_avatar_5
34 | - @mipmap/img_avatar_6
35 | - @mipmap/img_avatar_7
36 | - @mipmap/img_avatar_8
37 | - @mipmap/img_avatar_9
38 | - @mipmap/img_avatar_10
39 | - @mipmap/img_avatar_11
40 |
41 |
42 |
43 | - 0
44 | - 7
45 | - 8
46 | - 9
47 | - 10
48 | - 11
49 | - 12
50 | - 13
51 | - 14
52 | - 15
53 |
54 |
55 |
56 | - 0
57 | - 1
58 | - 2
59 | - 3
60 | - 4
61 | - 5
62 | - 7
63 | - 8
64 | - 9
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/model/Message.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.model;
2 |
3 | import com.google.gson.Gson;
4 |
5 | public class Message {
6 |
7 | public static final int MESSAGE_TYPE_TEXT = 0;
8 | public static final int MESSAGE_TYPE_IMAGE = 1;
9 | public static final int MESSAGE_TYPE_GIFT = 2;
10 | public static final int MESSAGE_TYPE_ORDER = 3;
11 |
12 | public static final String ORDER_TYPE_AUDIENCE = "toAudience";
13 | public static final String ORDER_TYPE_BROADCASTER = "toBroadcaster";
14 | public static final String ORDER_TYPE_MUTE = "mute";
15 |
16 | private int messageType = MESSAGE_TYPE_TEXT;
17 | private String orderType;
18 | private String content;
19 | private String sendId;
20 |
21 | public Message(String content, int sendId) {
22 | this.content = content;
23 | this.sendId = String.valueOf(sendId);
24 | }
25 |
26 | public Message(int messageType, String content, int sendId) {
27 | this(content, sendId);
28 | this.messageType = messageType;
29 | }
30 |
31 | public Message(String orderType, String content, int sendId) {
32 | this(content, sendId);
33 | this.messageType = MESSAGE_TYPE_ORDER;
34 | this.orderType = orderType;
35 | }
36 |
37 | public int getMessageType() {
38 | return messageType;
39 | }
40 |
41 | public void setMessageType(int messageType) {
42 | this.messageType = messageType;
43 | }
44 |
45 | public String getOrderType() {
46 | return orderType;
47 | }
48 |
49 | public void setOrderType(String orderType) {
50 | this.orderType = orderType;
51 | }
52 |
53 | public String getContent() {
54 | return content;
55 | }
56 |
57 | public void setContent(String content) {
58 | this.content = content;
59 | }
60 |
61 | public String getSendId() {
62 | return sendId;
63 | }
64 |
65 | public void setSendId(String sendId) {
66 | this.sendId = sendId;
67 | }
68 |
69 | public String toJsonString() {
70 | return new Gson().toJson(this);
71 | }
72 |
73 | public static Message fromJsonString(String str) {
74 | return new Gson().fromJson(str, Message.class);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/dialog_changer_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
27 |
28 |
39 |
40 |
41 |
42 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/util/MemberUtil.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.util;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.content.res.TypedArray;
6 | import android.text.TextUtils;
7 |
8 | import androidx.annotation.ArrayRes;
9 |
10 | import java.util.Random;
11 | import java.util.UUID;
12 |
13 | import io.agora.chatroom.ChatRoomApplication;
14 | import io.agora.chatroom.R;
15 |
16 | public class MemberUtil {
17 |
18 | private static SharedPreferences sp() {
19 | return ChatRoomApplication.instance.getSharedPreferences("member", Context.MODE_PRIVATE);
20 | }
21 |
22 | public static int getUserId() {
23 | int userId = sp().getInt("userId", 0);
24 | if (userId == 0) {
25 | userId = Math.abs(UUID.randomUUID().hashCode());
26 | sp().edit().putInt("userId", userId).apply();
27 | }
28 | return userId;
29 | }
30 |
31 | public static String getName() {
32 | String name = sp().getString("name", "");
33 | if (TextUtils.isEmpty(name)) {
34 | name = String.format("%s %s", randomName(R.array.random_surnames), randomName(R.array.random_names));
35 | sp().edit().putString("name", name).apply();
36 | }
37 | return name;
38 | }
39 |
40 | private static String randomName(@ArrayRes int resId) {
41 | String[] names = ChatRoomApplication.instance.getResources().getStringArray(resId);
42 | return names[new Random().nextInt(names.length - 1)];
43 | }
44 |
45 | public static int getAvatarIndex() {
46 | int avatarIndex = sp().getInt("avatarIndex", 0);
47 | if (avatarIndex == 0) {
48 | TypedArray images = ChatRoomApplication.instance.getResources().obtainTypedArray(R.array.random_avatar_images);
49 | int length = images.length();
50 | images.recycle();
51 | avatarIndex = new Random().nextInt(length - 1);
52 | sp().edit().putInt("avatarIndex", avatarIndex).apply();
53 | }
54 | return avatarIndex;
55 | }
56 |
57 | public static int getAvatarResId(int index) {
58 | TypedArray images = ChatRoomApplication.instance.getResources().obtainTypedArray(R.array.random_avatar_images);
59 | int resId = images.getResourceId(index, R.mipmap.ic_unkown);
60 | images.recycle();
61 | return resId;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/activity/ChannelGridActivity.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.activity;
2 |
3 | import android.content.Intent;
4 | import android.graphics.Rect;
5 | import android.os.Bundle;
6 | import android.view.View;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.appcompat.app.AppCompatActivity;
10 | import androidx.recyclerview.widget.GridLayoutManager;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | import butterknife.BindView;
14 | import butterknife.ButterKnife;
15 | import io.agora.chatroom.R;
16 | import io.agora.chatroom.adapter.ChannelGridAdapter;
17 | import io.agora.chatroom.model.Channel;
18 |
19 | public class ChannelGridActivity extends AppCompatActivity implements ChannelGridAdapter.OnItemClickListener {
20 |
21 | @BindView(R.id.rv_channel_grid)
22 | RecyclerView rv_channel_grid;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_channel_grid);
28 | ButterKnife.bind(this);
29 |
30 | initRecyclerView();
31 | }
32 |
33 | private void initRecyclerView() {
34 | rv_channel_grid.setHasFixedSize(true);
35 |
36 | ChannelGridAdapter adapter = new ChannelGridAdapter(this);
37 | adapter.setOnItemClickListener(this);
38 | rv_channel_grid.setAdapter(adapter);
39 |
40 | rv_channel_grid.setLayoutManager(new GridLayoutManager(this, 2));
41 |
42 | int spacing = getResources().getDimensionPixelSize(R.dimen.item_channel_spacing);
43 | rv_channel_grid.addItemDecoration(new RecyclerView.ItemDecoration() {
44 | @Override
45 | public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
46 | super.getItemOffsets(outRect, view, parent, state);
47 | outRect.set(spacing, spacing, spacing, spacing);
48 | }
49 | });
50 | }
51 |
52 | @Override
53 | public void onItemClick(View view, int position, Channel channel) {
54 | Intent intent = new Intent(ChannelGridActivity.this, ChatRoomActivity.class);
55 | intent.putExtra(ChatRoomActivity.BUNDLE_KEY_CHANNEL_ID, channel.getName());
56 | intent.putExtra(ChatRoomActivity.BUNDLE_KEY_BACKGROUND_RES, channel.getBackgroundRes());
57 | startActivity(intent);
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 语聊房
4 | 语聊房
5 | 房间列表
6 | 上麦
7 | 下麦
8 | 变声
9 | 伴奏
10 | 0
11 | 房间成员列表(%1$d人)
12 | 禁麦
13 | 解麦
14 | 封麦
15 | 解封
16 | 向主播赠送了礼物
17 | 说点什么…
18 | 音效
19 | 美声
20 | (主播)
21 |
22 |
23 | - 赵
24 | - 钱
25 | - 孙
26 | - 李
27 | - 周
28 | - 吴
29 | - 郑
30 | - 王
31 | - 冯
32 | - 陈
33 | - 褚
34 | - 卫
35 |
36 |
37 |
38 | - 富强
39 | - 民主
40 | - 文明
41 | - 和谐
42 | - 自由
43 | - 平等
44 | - 公正
45 | - 法治
46 | - 爱国
47 | - 敬业
48 | - 诚信
49 | - 友善
50 |
51 |
52 |
53 | - 原声
54 | - KTV
55 | - 演唱会
56 | - 大叔
57 | - 小姐姐
58 | - 录音棚
59 | - 流行
60 | - R&B
61 | - 留声机
62 |
63 |
64 |
65 | - 原声
66 | - 浑厚
67 | - 低沉
68 | - 圆润
69 | - 假音
70 | - 饱满
71 | - 清澈
72 | - 高亢
73 | - 嘹亮
74 | - 空旷
75 |
76 |
77 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/widget/GiftPopView.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.animation.AlphaAnimation;
8 | import android.view.animation.AnimationSet;
9 | import android.view.animation.TranslateAnimation;
10 | import android.widget.FrameLayout;
11 | import android.widget.ImageView;
12 | import android.widget.TextView;
13 |
14 | import androidx.annotation.Nullable;
15 |
16 | import butterknife.BindView;
17 | import butterknife.ButterKnife;
18 | import io.agora.chatroom.R;
19 | import io.agora.chatroom.manager.ChatRoomManager;
20 | import io.agora.chatroom.model.ChannelData;
21 | import io.agora.chatroom.model.Member;
22 |
23 | public class GiftPopView extends FrameLayout {
24 |
25 | @BindView(R.id.iv_avatar)
26 | ImageView iv_avatar;
27 | @BindView(R.id.tv_name)
28 | TextView tv_name;
29 |
30 | public GiftPopView(Context context) {
31 | super(context);
32 | init(context);
33 | }
34 |
35 | public GiftPopView(Context context, @Nullable AttributeSet attrs) {
36 | super(context, attrs);
37 | init(context);
38 | }
39 |
40 | public GiftPopView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
41 | super(context, attrs, defStyleAttr);
42 | init(context);
43 | }
44 |
45 | private void init(Context context) {
46 | LayoutInflater.from(context).inflate(R.layout.layout_gift, this);
47 | ButterKnife.bind(this);
48 | }
49 |
50 | public void show(String userId) {
51 | ChannelData channelData = ChatRoomManager.instance(getContext()).getChannelData();
52 | Member member = channelData.getMember(userId);
53 | if (member != null)
54 | tv_name.setText(member.getName());
55 | else
56 | tv_name.setText(userId);
57 | iv_avatar.setImageResource(channelData.getMemberAvatar(userId));
58 |
59 | setVisibility(View.VISIBLE);
60 | animation();
61 | postDelayed(() -> setVisibility(View.GONE), 2500);
62 | }
63 |
64 | private void animation() {
65 | AnimationSet animationSet = new AnimationSet(true);
66 | measure(0, 0);
67 | animationSet.addAnimation(new TranslateAnimation(0, 0, getMeasuredHeight(), 0));
68 | animationSet.addAnimation(new AlphaAnimation(0, 1));
69 | animationSet.setDuration(1000);
70 | startAnimation(animationSet);
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/VoiceChanger.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VoiceChanger.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/18.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum VoiceEffect: Int, CaseIterable {
12 | case DEFAULT = 0
13 | case KTV
14 | case LIVE
15 | case UNCLE
16 | case GIRL
17 | case STUDIO
18 | case POP = 7
19 | case RNB
20 | case PHONOGRAPH
21 |
22 | func description() -> String {
23 | switch self {
24 | case .DEFAULT:
25 | return NSLocalizedString("Default", comment: "")
26 | case .KTV:
27 | return NSLocalizedString("KTV", comment: "")
28 | case .LIVE:
29 | return NSLocalizedString("Live", comment: "")
30 | case .UNCLE:
31 | return NSLocalizedString("Uncle", comment: "")
32 | case .GIRL:
33 | return NSLocalizedString("Girl", comment: "")
34 | case .STUDIO:
35 | return NSLocalizedString("Studio", comment: "")
36 | case .POP:
37 | return NSLocalizedString("Pop", comment: "")
38 | case .RNB:
39 | return NSLocalizedString("R&B", comment: "")
40 | case .PHONOGRAPH:
41 | return NSLocalizedString("Phonograph", comment: "")
42 | }
43 | }
44 | }
45 |
46 | enum VoiceBeautify: Int, CaseIterable {
47 | case DEFAULT = 0
48 | case THICK = 7
49 | case LOW
50 | case ROUND
51 | case FALSETTO
52 | case FULL
53 | case CLEAR
54 | case RESOUNDING
55 | case LOUD
56 | case OPENAIR
57 |
58 | func description() -> String {
59 | switch self {
60 | case .DEFAULT:
61 | return NSLocalizedString("Default", comment: "")
62 | case .THICK:
63 | return NSLocalizedString("Thick", comment: "")
64 | case .LOW:
65 | return NSLocalizedString("Low", comment: "")
66 | case .ROUND:
67 | return NSLocalizedString("Round", comment: "")
68 | case .FALSETTO:
69 | return NSLocalizedString("Falsetto", comment: "")
70 | case .FULL:
71 | return NSLocalizedString("Full", comment: "")
72 | case .CLEAR:
73 | return NSLocalizedString("Clear", comment: "")
74 | case .RESOUNDING:
75 | return NSLocalizedString("Resounding", comment: "")
76 | case .LOUD:
77 | return NSLocalizedString("Loud", comment: "")
78 | case .OPENAIR:
79 | return NSLocalizedString("OpenAir", comment: "")
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/layout_gift.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
20 |
21 |
29 |
30 |
36 |
37 |
44 |
45 |
46 |
47 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/ChannelViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelCollectionViewController.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/5.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AgoraRtmKit
11 |
12 | class ChannelViewController: UIViewController {
13 | let mChannelArray: [Channel] = [
14 | Channel(drawableRes: #imageLiteral(resourceName: "img_channel_0"), backgroundRes: #imageLiteral(resourceName: "bg_channel_0"), name: "001"),
15 | Channel(drawableRes: #imageLiteral(resourceName: "img_channel_1"), backgroundRes: #imageLiteral(resourceName: "bg_channel_1"), name: "002"),
16 | Channel(drawableRes: #imageLiteral(resourceName: "img_channel_2"), backgroundRes: #imageLiteral(resourceName: "bg_channel_2"), name: "003"),
17 | Channel(drawableRes: #imageLiteral(resourceName: "img_channel_3"), backgroundRes: #imageLiteral(resourceName: "bg_channel_3"), name: "004"),
18 | Channel(drawableRes: #imageLiteral(resourceName: "img_channel_4"), backgroundRes: #imageLiteral(resourceName: "bg_channel_4"), name: "005"),
19 | ]
20 |
21 | override var preferredStatusBarStyle: UIStatusBarStyle {
22 | .lightContent
23 | }
24 |
25 | // MARK: - Navigation
26 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
27 | switch segue.identifier {
28 | case "chatRoom":
29 | let channel = sender as! Channel
30 | let vc = segue.destination as! ChatRoomViewController
31 | vc.bgImg = channel.backgroundRes
32 | vc.title = channel.name
33 | break;
34 | default:
35 | break;
36 | }
37 | }
38 | }
39 |
40 | extension ChannelViewController: UICollectionViewDataSource {
41 | // MARK: - UICollectionViewDataSource
42 |
43 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
44 | mChannelArray.count
45 | }
46 |
47 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
48 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ChannelCell", for: indexPath) as! ChannelCell
49 |
50 | cell.update(mChannelArray[indexPath.row])
51 |
52 | return cell
53 | }
54 | }
55 |
56 | extension ChannelViewController: UICollectionViewDelegate {
57 | // MARK: - UICollectionViewDelegate
58 |
59 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
60 | self.performSegue(withIdentifier: "chatRoom", sender: mChannelArray[indexPath.row])
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ChatRoom
3 | ChatRoom
4 | ChannelList
5 | toBroadcast
6 | toAudience
7 | Mixing
8 | 0
9 | Channel member list(%1$d people)
10 | Turn off mic
11 | Turn on mic
12 | Open
13 | Give gift to anchor
14 | Say something…
15 | Voice Effect
16 | (Anchor)
17 | Changer
18 | Voice Beautify
19 | Close
20 |
21 |
22 | - Zhao
23 | - Qian
24 | - Sun
25 | - Li
26 | - Zhou
27 | - Wu
28 | - Zheng
29 | - Wang
30 | - Feng
31 | - Chen
32 | - Chu
33 | - Wei
34 |
35 |
36 |
37 | - Fuqiang
38 | - Minzhu
39 | - Wenming
40 | - Hexie
41 | - Ziyou
42 | - Pingdeng
43 | - Gongzheng
44 | - Fazhi
45 | - Aiguo
46 | - Jingye
47 | - Chengxin
48 | - Youshan
49 |
50 |
51 |
52 | - Default
53 | - KTV
54 | - Live
55 | - Uncle
56 | - Girl
57 | - Studio
58 | - Pop
59 | - R&B
60 | - Phonograph
61 |
62 |
63 |
64 | - Default
65 | - Thick
66 | - Low
67 | - Round
68 | - Falsetto
69 | - Full
70 | - Clear
71 | - Resounding
72 | - Loud
73 | - OpenAir
74 |
75 |
76 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/MemberViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemberViewController.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/26.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MemberViewController: UIViewController {
12 | @IBOutlet weak var num: UILabel!
13 | @IBOutlet weak var listMember: UITableView!
14 |
15 | private var mChannelData = ChatRoomManager.shared.getChannelData()
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 | refreshTitle()
20 | }
21 |
22 | func refreshTitle() {
23 | num.text = "\(NSLocalizedString("channel_member_list", comment: ""))(\(mChannelData.getMemberArray().count)\(NSLocalizedString("people", comment: "")))"
24 | }
25 |
26 | func reloadData() {
27 | refreshTitle()
28 | listMember.reloadData()
29 | }
30 |
31 | func reloadRowsByUserId(_ userId: String) {
32 | let index = mChannelData.indexOfMemberArray(userId)
33 | if index != NSNotFound {
34 | listMember.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)
35 | }
36 | }
37 |
38 | @IBAction func onClick(_ sender: UIButton) {
39 | self.dismiss(animated: true, completion: nil)
40 | }
41 | }
42 |
43 | extension MemberViewController: UITableViewDataSource {
44 | // MARK: - UITableViewDataSource
45 |
46 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
47 | mChannelData.getMemberArray().count
48 | }
49 |
50 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
51 | let cell = tableView.dequeueReusableCell(withIdentifier: "MemberCell", for: indexPath) as! MemberCell
52 |
53 | cell.selectionStyle = .none
54 | cell.update(mChannelData, indexPath.row)
55 | cell.role.tag = indexPath.row
56 | cell.role.addTarget(self, action: #selector(role(_:)), for: .touchUpInside)
57 | cell.btnMute.tag = indexPath.row
58 | cell.btnMute.addTarget(self, action: #selector(mute(_:)), for: .touchUpInside)
59 |
60 | return cell
61 | }
62 |
63 | @objc private func role(_ sender: UIButton) {
64 | let userId = mChannelData.getMemberArray()[sender.tag].userId
65 | if mChannelData.isUserOnline(userId) {
66 | ChatRoomManager.shared.toAudience(userId, nil)
67 | } else {
68 | ChatRoomManager.shared.toBroadcaster(userId, mChannelData.firstIndexOfEmptySeat())
69 | }
70 | }
71 |
72 | @objc private func mute(_ sender: UIButton) {
73 | let userId = mChannelData.getMemberArray()[sender.tag].userId
74 | ChatRoomManager.shared.muteMic(userId, !mChannelData.isUserMuted(userId))
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/widget/VoiceChangerGridRecyclerView.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Rect;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 | import androidx.recyclerview.widget.GridLayoutManager;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | import io.agora.chatroom.R;
14 | import io.agora.chatroom.adapter.VoiceChangerGridAdapter;
15 |
16 | public class VoiceChangerGridRecyclerView extends RecyclerView {
17 |
18 | private VoiceChangerGridAdapter mEffectAdapter;
19 | private VoiceChangerGridAdapter mBeautifyAdapter;
20 |
21 | public VoiceChangerGridRecyclerView(@NonNull Context context) {
22 | super(context);
23 | init(context);
24 | }
25 |
26 | public VoiceChangerGridRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
27 | super(context, attrs);
28 | init(context);
29 | }
30 |
31 | public VoiceChangerGridRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
32 | super(context, attrs, defStyleAttr);
33 | init(context);
34 | }
35 |
36 | private void init(Context context) {
37 | setHasFixedSize(true);
38 |
39 | mEffectAdapter = new VoiceChangerGridAdapter(context, R.array.voice_effect_keys, R.array.voice_effect_values);
40 | mBeautifyAdapter = new VoiceChangerGridAdapter(context, R.array.voice_beautify_keys, R.array.voice_beautify_values);
41 |
42 | setLayoutManager(new GridLayoutManager(context, 3));
43 |
44 | int spacing = getResources().getDimensionPixelSize(R.dimen.dialog_member_item_spacing);
45 | addItemDecoration(new RecyclerView.ItemDecoration() {
46 | @Override
47 | public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
48 | super.getItemOffsets(outRect, view, parent, state);
49 | outRect.set(spacing / 2, spacing, spacing / 2, 0);
50 | }
51 | });
52 | }
53 |
54 | public void showEffect(int selectedIndex) {
55 | setAdapter(mEffectAdapter);
56 | mEffectAdapter.setSelectedIndex(selectedIndex);
57 | }
58 |
59 | public void showBeautify(int selectedIndex) {
60 | setAdapter(mBeautifyAdapter);
61 | mBeautifyAdapter.setSelectedIndex(selectedIndex);
62 | }
63 |
64 | public void setOnItemClickListener(VoiceChangerGridAdapter.OnItemClickListener listener) {
65 | mEffectAdapter.setOnItemClickListener(listener);
66 | mBeautifyAdapter.setOnItemClickListener(listener);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/adapter/MessageListAdapter.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 | import android.widget.TextView;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | import butterknife.BindView;
14 | import butterknife.ButterKnife;
15 | import io.agora.chatroom.R;
16 | import io.agora.chatroom.model.ChannelData;
17 | import io.agora.chatroom.model.Member;
18 | import io.agora.chatroom.model.Message;
19 | import io.agora.chatroom.manager.ChatRoomManager;
20 |
21 | public class MessageListAdapter extends RecyclerView.Adapter {
22 |
23 | private LayoutInflater mInflater;
24 |
25 | private ChannelData mChannelData;
26 |
27 | public MessageListAdapter(Context context) {
28 | mInflater = LayoutInflater.from(context);
29 | mChannelData = ChatRoomManager.instance(context).getChannelData();
30 | }
31 |
32 | @NonNull
33 | @Override
34 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
35 | View view = mInflater.inflate(R.layout.layout_item_message, parent, false);
36 | return new ViewHolder(view);
37 | }
38 |
39 | @Override
40 | public int getItemCount() {
41 | if (mChannelData == null) return 0;
42 | return mChannelData.getMessageList().size();
43 | }
44 |
45 | @Override
46 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
47 | Message message = mChannelData.getMessageList().get(position);
48 | String userId = message.getSendId();
49 |
50 | holder.iv_avatar.setImageResource(mChannelData.getMemberAvatar(userId));
51 |
52 | switch (message.getMessageType()) {
53 | case Message.MESSAGE_TYPE_TEXT:
54 | holder.tv_message.setVisibility(View.VISIBLE);
55 | Member member = mChannelData.getMember(userId);
56 | holder.tv_message.setText(String.format("%s:%s", member != null ? member.getName() : userId, message.getContent()));
57 | break;
58 | case Message.MESSAGE_TYPE_IMAGE:
59 | // TODO
60 | break;
61 | }
62 | }
63 |
64 | class ViewHolder extends RecyclerView.ViewHolder {
65 | @BindView(R.id.iv_avatar)
66 | ImageView iv_avatar;
67 | @BindView(R.id.tv_message)
68 | TextView tv_message;
69 | @BindView(R.id.iv_image)
70 | ImageView iv_image;
71 |
72 | ViewHolder(View view) {
73 | super(view);
74 | ButterKnife.bind(this, view);
75 | }
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/adapter/VoiceChangerGridAdapter.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import androidx.annotation.ArrayRes;
10 | import androidx.annotation.NonNull;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | import butterknife.BindView;
14 | import butterknife.ButterKnife;
15 | import io.agora.chatroom.R;
16 |
17 | public class VoiceChangerGridAdapter extends RecyclerView.Adapter {
18 |
19 | private LayoutInflater mInflater;
20 | private VoiceChangerGridAdapter.OnItemClickListener mListener;
21 | private int mSelectedIndex;
22 |
23 | private String[] mKeys;
24 | private int[] mValues;
25 |
26 | public VoiceChangerGridAdapter(Context context, @ArrayRes int keysId, @ArrayRes int valuesId) {
27 | mInflater = LayoutInflater.from(context);
28 | mKeys = context.getResources().getStringArray(keysId);
29 | mValues = context.getResources().getIntArray(valuesId);
30 | }
31 |
32 | @NonNull
33 | @Override
34 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
35 | View view = mInflater.inflate(R.layout.layout_item_changer, parent, false);
36 | return new ViewHolder(view);
37 | }
38 |
39 | @Override
40 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
41 | String key = mKeys[position];
42 |
43 | holder.tv_changer.setText(key);
44 | holder.tv_changer.setBackgroundResource(mSelectedIndex == position ? R.drawable.bg_changer_item_selected : R.drawable.bg_changer_item_normal);
45 |
46 | holder.tv_changer.setOnClickListener((view) -> {
47 | setSelectedIndex(position);
48 | if (mListener != null)
49 | mListener.onItemClick(position, mValues[position]);
50 | });
51 | }
52 |
53 | @Override
54 | public int getItemCount() {
55 | if (mKeys == null) return 0;
56 | return mKeys.length;
57 | }
58 |
59 | public void setSelectedIndex(int index) {
60 | notifyItemChanged(mSelectedIndex);
61 | mSelectedIndex = index;
62 | notifyItemChanged(index);
63 | }
64 |
65 | public void setOnItemClickListener(VoiceChangerGridAdapter.OnItemClickListener listener) {
66 | mListener = listener;
67 | }
68 |
69 | class ViewHolder extends RecyclerView.ViewHolder {
70 | @BindView(R.id.tv_changer)
71 | TextView tv_changer;
72 |
73 | ViewHolder(View view) {
74 | super(view);
75 | ButterKnife.bind(this, view);
76 | }
77 | }
78 |
79 | public interface OnItemClickListener {
80 | void onItemClick(int position, int value);
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/util/AlertUtil.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.util;
2 |
3 | import android.content.Context;
4 | import android.content.DialogInterface;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 | import android.view.View;
8 | import android.widget.PopupWindow;
9 | import android.widget.Toast;
10 |
11 | import androidx.appcompat.app.AlertDialog;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | import io.agora.chatroom.ChatRoomApplication;
17 | import io.agora.chatroom.R;
18 | import me.kareluo.ui.OptionMenu;
19 | import me.kareluo.ui.OptionMenuView;
20 | import me.kareluo.ui.PopupMenuView;
21 | import me.kareluo.ui.PopupView;
22 |
23 | public class AlertUtil {
24 |
25 | public static void showToast(String format, Object... args) {
26 | new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(ChatRoomApplication.instance, String.format(format, args), Toast.LENGTH_SHORT).show());
27 | }
28 |
29 | public static void showPop(Context context, View view, int[] ids, OptionMenuView.OnOptionMenuClickListener clickListener, PopupWindow.OnDismissListener dismissListener) {
30 | PopupMenuView popupMenuView = new PopupMenuView(context);
31 | List menus = new ArrayList<>();
32 | for (int id : ids) {
33 | int strId = 0;
34 | switch (id) {
35 | case R.id.to_audience:
36 | strId = R.string.to_audience;
37 | break;
38 | case R.id.to_broadcast:
39 | strId = R.string.to_broadcast;
40 | break;
41 | case R.id.turn_off_mic:
42 | strId = R.string.turn_off_mic;
43 | break;
44 | case R.id.turn_on_mic:
45 | strId = R.string.turn_on_mic;
46 | break;
47 | case R.id.close_seat:
48 | strId = R.string.close_seat;
49 | break;
50 | case R.id.open_seat:
51 | strId = R.string.open_seat;
52 | break;
53 | }
54 | menus.add(new OptionMenu(id, strId));
55 | }
56 | popupMenuView.setMenuItems(menus);
57 | popupMenuView.setSites(PopupView.SITE_BOTTOM, PopupView.SITE_LEFT, PopupView.SITE_TOP, PopupView.SITE_RIGHT);
58 | popupMenuView.setOnMenuClickListener(clickListener);
59 | popupMenuView.setOnDismissListener(dismissListener);
60 | popupMenuView.show(view);
61 | }
62 |
63 | public static void showAlertDialog(Context context, String text, String action, DialogInterface.OnClickListener listener) {
64 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
65 | builder.setTitle(text);
66 | builder.setPositiveButton(action, listener);
67 | builder.create().show();
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/layout_item_member.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
19 |
20 |
33 |
34 |
46 |
47 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/MemberUtil.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemberUtil.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/12/5.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct MemberUtil {
12 | static let surNames = [NSLocalizedString("Zhao", comment: ""), NSLocalizedString("Qian", comment: ""), NSLocalizedString("Sun", comment: ""), NSLocalizedString("Li", comment: ""), NSLocalizedString("Zhou", comment: ""), NSLocalizedString("Wu", comment: ""), NSLocalizedString("Zheng", comment: ""), NSLocalizedString("Wang", comment: ""), NSLocalizedString("Feng", comment: ""), NSLocalizedString("Chen", comment: ""), NSLocalizedString("Chu", comment: ""), NSLocalizedString("Wei", comment: "")]
13 | static let names = [NSLocalizedString("Fuqiang", comment: ""), NSLocalizedString("Minzhu", comment: ""), NSLocalizedString("Wenming", comment: ""), NSLocalizedString("Hexie", comment: ""), NSLocalizedString("Ziyou", comment: ""), NSLocalizedString("Pingdeng", comment: ""), NSLocalizedString("Gongzheng", comment: ""), NSLocalizedString("Fazhi", comment: ""), NSLocalizedString("Aiguo", comment: ""), NSLocalizedString("Jingye", comment: ""), NSLocalizedString("Chengxin", comment: ""), NSLocalizedString("Youshan", comment: "")]
14 | static let avatarImages: [UIImage] = [#imageLiteral(resourceName: "img_header_0"), #imageLiteral(resourceName: "img_header_1"), #imageLiteral(resourceName: "img_header_2"), #imageLiteral(resourceName: "img_header_3"), #imageLiteral(resourceName: "img_header_4"), #imageLiteral(resourceName: "img_header_5"), #imageLiteral(resourceName: "img_header_6"), #imageLiteral(resourceName: "img_header_7"), #imageLiteral(resourceName: "img_header_8"), #imageLiteral(resourceName: "img_header_9"), #imageLiteral(resourceName: "img_header_10"), #imageLiteral(resourceName: "img_header_11")]
15 |
16 | static func getUserId() -> Int32 {
17 | var userId = Int32(truncatingIfNeeded: UserDefaults.standard.integer(forKey: "userId"))
18 | if userId == 0 {
19 | userId = abs(Int32(truncatingIfNeeded: UUID().uuidString.hashValue))
20 | UserDefaults.standard.set(userId, forKey: "userId")
21 | UserDefaults.standard.synchronize()
22 | }
23 | return userId
24 | }
25 |
26 | static func getName() -> String {
27 | guard let name = UserDefaults.standard.string(forKey: "name") else {
28 | let name = "\(randomName(surNames)) \(randomName(names))"
29 | UserDefaults.standard.set(name, forKey: "name")
30 | UserDefaults.standard.synchronize()
31 | return name
32 | }
33 | return name
34 | }
35 |
36 | private static func randomName(_ strArray: [String]) -> String {
37 | strArray[Int.random(in: 0.. Int {
41 | var avatarIndex = UserDefaults.standard.integer(forKey: "avatarIndex")
42 | if avatarIndex == 0 {
43 | avatarIndex = Int.random(in: 0.. UIImage {
51 | avatarImages[index]
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/adapter/ChannelGridAdapter.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.adapter;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.content.res.TypedArray;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.recyclerview.widget.RecyclerView;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | import butterknife.BindView;
19 | import butterknife.ButterKnife;
20 | import io.agora.chatroom.R;
21 | import io.agora.chatroom.model.Channel;
22 |
23 | public class ChannelGridAdapter extends RecyclerView.Adapter {
24 |
25 | private LayoutInflater mInflater;
26 | private OnItemClickListener mListener;
27 |
28 | private List mChannelList;
29 |
30 | public ChannelGridAdapter(Context context) {
31 | mInflater = LayoutInflater.from(context);
32 | initData(context);
33 | }
34 |
35 | private void initData(Context context) {
36 | mChannelList = new ArrayList<>();
37 |
38 | Resources resources = context.getResources();
39 | TypedArray drawables = resources.obtainTypedArray(R.array.channel_list_drawable);
40 | TypedArray backgrounds = resources.obtainTypedArray(R.array.channel_list_background);
41 | String[] titles = resources.getStringArray(R.array.channel_list_title);
42 |
43 | for (int i = 0; i < titles.length; i++) {
44 | mChannelList.add(new Channel(
45 | drawables.getResourceId(i, 0),
46 | backgrounds.getResourceId(i, 0),
47 | titles[i]
48 | ));
49 | }
50 |
51 | drawables.recycle();
52 | backgrounds.recycle();
53 | }
54 |
55 | @NonNull
56 | @Override
57 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
58 | View view = mInflater.inflate(R.layout.layout_item_channel, parent, false);
59 | return new ViewHolder(view);
60 | }
61 |
62 | @Override
63 | public int getItemCount() {
64 | if (mChannelList == null) return 0;
65 | return mChannelList.size();
66 | }
67 |
68 | @Override
69 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
70 | Channel channel = mChannelList.get(position);
71 |
72 | holder.iv_image.setImageResource(channel.getDrawableRes());
73 | holder.tv_name.setText(channel.getName());
74 |
75 | holder.view.setOnClickListener((view) -> {
76 | if (mListener != null)
77 | mListener.onItemClick(view, position, channel);
78 | });
79 | }
80 |
81 | public void setOnItemClickListener(OnItemClickListener listener) {
82 | mListener = listener;
83 | }
84 |
85 | class ViewHolder extends RecyclerView.ViewHolder {
86 | View view;
87 | @BindView(R.id.iv_image)
88 | ImageView iv_image;
89 | @BindView(R.id.tv_name)
90 | TextView tv_name;
91 |
92 | ViewHolder(View view) {
93 | super(view);
94 | this.view = view;
95 | ButterKnife.bind(this, view);
96 | }
97 | }
98 |
99 | public interface OnItemClickListener {
100 | void onItemClick(View view, int position, Channel channel);
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 17sp
3 | 15dp
4 | 14dp
5 | 6dp
6 | 10dp
7 | 0.5dp
8 | 1dp
9 | 19dp
10 |
11 |
12 | 10dp
13 | 15dp
14 | 12dp
15 | 14sp
16 |
17 |
18 | 30dp
19 | 62dp
20 | 34dp
21 | 17sp
22 | 25dp
23 |
24 | 10dp
25 | 60dp
26 | 50dp
27 | 25dp
28 |
29 | 15dp
30 | 30dp
31 | 8dp
32 | 15dp
33 | 9dp
34 | 14sp
35 |
36 | 15dp
37 | 12dp
38 | 14sp
39 | 9dp
40 | 38dp
41 | 17sp
42 |
43 | 220dp
44 | 56dp
45 | 28dp
46 | 4dp
47 | 11dp
48 | 48dp
49 | 14sp
50 | 12sp
51 |
52 | 350dp
53 | 15dp
54 | 55dp
55 | 28dp
56 | 17sp
57 | 100dp
58 | 44dp
59 | 22dp
60 |
61 |
62 | 325dp
63 | 375dp
64 | 16dp
65 | 18dp
66 | 14sp
67 | 26dp
68 | 14sp
69 | 19dp
70 |
71 | 19dp
72 | 36dp
73 | 46dp
74 | 32dp
75 | 12sp
76 | 12dp
77 |
78 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/widget/VoiceChangerDialog.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.widget;
2 |
3 | import android.app.Dialog;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.view.Gravity;
7 | import android.view.Window;
8 | import android.view.WindowManager;
9 | import android.widget.RadioGroup;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.annotation.Nullable;
13 | import androidx.fragment.app.DialogFragment;
14 |
15 | import butterknife.BindView;
16 | import butterknife.ButterKnife;
17 | import io.agora.chatroom.R;
18 | import io.agora.chatroom.adapter.VoiceChangerGridAdapter;
19 | import io.agora.chatroom.manager.ChatRoomManager;
20 | import io.agora.chatroom.manager.RtcManager;
21 |
22 | public class VoiceChangerDialog extends DialogFragment implements VoiceChangerGridAdapter.OnItemClickListener, RadioGroup.OnCheckedChangeListener {
23 |
24 | @BindView(R.id.rg_title)
25 | RadioGroup rg_title;
26 | @BindView(R.id.rv_changer_grid)
27 | VoiceChangerGridRecyclerView rv_changer_grid;
28 |
29 | private Context mContext;
30 |
31 | private int mEffectSelectedIndex;
32 | private int mBeautifySelectedIndex;
33 |
34 | @Override
35 | public void onAttach(@NonNull Context context) {
36 | super.onAttach(context);
37 | mContext = context;
38 | }
39 |
40 | @NonNull
41 | @Override
42 | public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
43 | Dialog dialog = new Dialog(mContext);
44 | dialog.setContentView(R.layout.dialog_changer_grid);
45 |
46 | ButterKnife.bind(this, dialog);
47 |
48 | initView();
49 | return dialog;
50 | }
51 |
52 | @Override
53 | public void onStart() {
54 | super.onStart();
55 | Dialog dialog = getDialog();
56 | if (dialog != null) {
57 | Window window = dialog.getWindow();
58 | if (window != null) {
59 | window.setBackgroundDrawableResource(android.R.color.transparent);
60 | WindowManager.LayoutParams params = window.getAttributes();
61 | params.gravity = Gravity.BOTTOM;
62 | params.width = WindowManager.LayoutParams.MATCH_PARENT;
63 | params.height = WindowManager.LayoutParams.WRAP_CONTENT;
64 | window.setAttributes(params);
65 | }
66 | }
67 | }
68 |
69 | @Override
70 | public void onResume() {
71 | super.onResume();
72 | rg_title.check(R.id.rb_effect);
73 | }
74 |
75 | private void initView() {
76 | rg_title.setOnCheckedChangeListener(this);
77 | rv_changer_grid.setOnItemClickListener(this);
78 | }
79 |
80 | @Override
81 | public void onCheckedChanged(RadioGroup group, int checkedId) {
82 | switch (checkedId) {
83 | case R.id.rb_effect:
84 | rv_changer_grid.showEffect(mEffectSelectedIndex);
85 | break;
86 | case R.id.rb_beautify:
87 | rv_changer_grid.showBeautify(mBeautifySelectedIndex);
88 | break;
89 | }
90 | }
91 |
92 | @Override
93 | public void onItemClick(int position, int value) {
94 | RtcManager manager = ChatRoomManager.instance(mContext).getRtcManager();
95 | switch (rg_title.getCheckedRadioButtonId()) {
96 | case R.id.rb_effect:
97 | mEffectSelectedIndex = position;
98 | manager.setReverbPreset(value);
99 | break;
100 | case R.id.rb_beautify:
101 | mBeautifySelectedIndex = position;
102 | manager.setVoiceChanger(value);
103 | break;
104 | }
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/activity_chat_room.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
27 |
28 |
36 |
37 |
50 |
51 |
52 |
53 |
62 |
63 |
69 |
70 |
76 |
77 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/iOS/AgoraChatRoom/VoiceChangerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VoiceChangerViewController.swift
3 | // AgoraChatRoom
4 | //
5 | // Created by LXH on 2019/11/27.
6 | // Copyright © 2019 CavanSu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import AgoraRtcKit
12 |
13 | class VoiceChangerViewController: UIViewController {
14 | @IBOutlet weak var gridVoiceEffect: UICollectionView!
15 | @IBOutlet weak var effect: UIButton!
16 | @IBOutlet weak var lineEffect: UIView!
17 | @IBOutlet weak var beautify: UIButton!
18 | @IBOutlet weak var lineBeautify: UIView!
19 |
20 | private var isEffect = true
21 | private var mEffectSelectedIndex = 0
22 | private var mBeautifySelectedIndex = 0
23 |
24 | func showEffect(_ selectedIndex: Int) {
25 | isEffect = true
26 | mEffectSelectedIndex = selectedIndex
27 | gridVoiceEffect.reloadData()
28 | }
29 |
30 | func showBeautify(_ selectedIndex: Int) {
31 | isEffect = false
32 | mBeautifySelectedIndex = selectedIndex
33 | gridVoiceEffect.reloadData()
34 | }
35 |
36 | private func resetViews() {
37 | effect.isSelected = isEffect
38 | lineEffect.isHidden = !isEffect
39 | beautify.isSelected = !isEffect
40 | lineBeautify.isHidden = isEffect
41 | }
42 |
43 | override func touchesEnded(_ touches: Set, with event: UIEvent?) {
44 | super.touchesEnded(touches, with: event)
45 | dismiss(animated: true)
46 | }
47 |
48 | @IBAction func onEffectClick(_ sender: UIButton) {
49 | showEffect(mEffectSelectedIndex)
50 | resetViews()
51 | }
52 |
53 | @IBAction func onBeautifyClick(_ sender: UIButton) {
54 | showBeautify(mBeautifySelectedIndex)
55 | resetViews()
56 | }
57 | }
58 |
59 | extension VoiceChangerViewController: UICollectionViewDelegate {
60 | // MARK: - UICollectionViewDelegate
61 |
62 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
63 | let position = indexPath.item
64 | if isEffect {
65 | if position == mEffectSelectedIndex {
66 | return
67 | }
68 | let oldPosition = mEffectSelectedIndex
69 | mEffectSelectedIndex = position
70 | gridVoiceEffect.reloadItems(at: [IndexPath(item: oldPosition, section: 0), indexPath])
71 |
72 | let type = VoiceEffect.allCases[position].rawValue
73 | ChatRoomManager.shared.getRtcManager().setReverbPreset(type)
74 | } else {
75 | if position == mBeautifySelectedIndex {
76 | return
77 | }
78 | let oldPosition = mBeautifySelectedIndex
79 | mBeautifySelectedIndex = position
80 | gridVoiceEffect.reloadItems(at: [IndexPath(item: oldPosition, section: 0), indexPath])
81 |
82 | let type = VoiceBeautify.allCases[position].rawValue
83 | ChatRoomManager.shared.getRtcManager().setVoiceChanger(type)
84 | }
85 | }
86 | }
87 |
88 | extension VoiceChangerViewController: UICollectionViewDataSource {
89 | // MARK: - UICollectionViewDataSource
90 |
91 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
92 | isEffect ? VoiceEffect.allCases.count : VoiceBeautify.allCases.count
93 | }
94 |
95 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
96 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VoiceChangerCell", for: indexPath) as! VoiceChangerCell
97 |
98 | cell.update(isEffect, mEffectSelectedIndex, mBeautifySelectedIndex, indexPath.item)
99 |
100 | return cell
101 | }
102 | }
103 |
104 | extension VoiceChangerViewController: UICollectionViewDelegateFlowLayout {
105 | // MARK: - UICollectionViewDelegateFlowLayout
106 |
107 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
108 | let width = UIApplication.shared.windows[0].bounds.size.width
109 | return CGSize.init(width: Int((width - 19 * 4) / 3), height: 44)
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Android/app/src/main/res/layout/layout_chat_room_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
25 |
26 |
42 |
43 |
57 |
58 |
67 |
68 |
77 |
78 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/Android/app/src/main/java/io/agora/chatroom/adapter/SeatGridAdapter.java:
--------------------------------------------------------------------------------
1 | package io.agora.chatroom.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | import java.util.List;
13 |
14 | import butterknife.BindView;
15 | import butterknife.ButterKnife;
16 | import de.hdodenhof.circleimageview.CircleImageView;
17 | import io.agora.chatroom.R;
18 | import io.agora.chatroom.model.ChannelData;
19 | import io.agora.chatroom.model.Seat;
20 | import io.agora.chatroom.manager.ChatRoomManager;
21 | import io.agora.chatroom.widget.SpreadView;
22 |
23 | public class SeatGridAdapter extends RecyclerView.Adapter {
24 |
25 | private LayoutInflater mInflater;
26 | private OnItemClickListener mListener;
27 |
28 | private ChannelData mChannelData;
29 |
30 | public SeatGridAdapter(Context context) {
31 | mInflater = LayoutInflater.from(context);
32 | mChannelData = ChatRoomManager.instance(context).getChannelData();
33 | }
34 |
35 | @NonNull
36 | @Override
37 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
38 | View view = mInflater.inflate(R.layout.layout_item_seat, parent, false);
39 | return new ViewHolder(view);
40 | }
41 |
42 | @Override
43 | public int getItemCount() {
44 | if (mChannelData == null) return 0;
45 | return mChannelData.getSeatArray().length;
46 | }
47 |
48 | @Override
49 | public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List