parent
fd8c4e726d
commit
6f86663a54
|
@ -3,6 +3,8 @@
|
|||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application
|
||||
android:name=".app.SodaLiveApp"
|
||||
|
@ -38,6 +40,21 @@
|
|||
<activity
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
|
||||
android:theme="@style/Theme.AppCompat.DayNight" />
|
||||
</application>
|
||||
|
||||
<!-- [START firebase_service] -->
|
||||
<service
|
||||
android:name=".fcm.SodaFirebaseMessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<!-- [END firebase_service] -->
|
||||
|
||||
<!-- [START fcm_default_channel] -->
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||
android:value="@string/default_notification_channel_id" />
|
||||
<!-- [END fcm_default_channel] -->
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
|
@ -8,12 +8,14 @@ object Constants {
|
|||
const val PREF_IS_ADULT = "pref_is_adult"
|
||||
const val PREF_NICKNAME = "pref_nickname"
|
||||
const val PREF_USER_ROLE = "pref_user_role"
|
||||
const val PREF_PUSH_TOKEN = "pref_push_token"
|
||||
const val PREF_PROFILE_IMAGE = "pref_profile_image"
|
||||
|
||||
const val EXTRA_DATA = "extra_data"
|
||||
const val EXTRA_TERMS = "extra_terms"
|
||||
const val EXTRA_USER_ID = "extra_user_id"
|
||||
const val EXTRA_ROOM_ID = "extra_room_id"
|
||||
const val EXTRA_MESSAGE_ID = "extra_message_id"
|
||||
|
||||
const val EXTRA_AUDIO_CONTENT_ID = "extra_audio_content_id"
|
||||
const val EXTRA_CONTENT_ID = "extra_content_id"
|
||||
}
|
||||
|
|
|
@ -92,4 +92,10 @@ object SharedPreferenceManager {
|
|||
set(value) {
|
||||
sharedPreferences[Constants.PREF_IS_ADULT] = value
|
||||
}
|
||||
|
||||
var pushToken: String
|
||||
get() = sharedPreferences[Constants.PREF_PUSH_TOKEN, ""]
|
||||
set(value) {
|
||||
sharedPreferences[Constants.PREF_PUSH_TOKEN] = value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
package kr.co.vividnext.sodalive.fcm
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.RingtoneManager
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.splash.SplashActivity
|
||||
|
||||
class SodaFirebaseMessagingService : FirebaseMessagingService() {
|
||||
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
||||
if (SharedPreferenceManager.token.isNotBlank()) {
|
||||
when {
|
||||
remoteMessage.data.isNotEmpty() -> {
|
||||
sendNotification(remoteMessage.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewToken(token: String) {
|
||||
SharedPreferenceManager.pushToken = token
|
||||
}
|
||||
|
||||
private fun sendNotification(messageData: Map<String, String>) {
|
||||
val notificationChannelId = getString(R.string.default_notification_channel_id)
|
||||
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
val notificationManager =
|
||||
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Since android Oreo notification channel is needed.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel =
|
||||
NotificationChannel(
|
||||
notificationChannelId,
|
||||
getString(R.string.app_name),
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
val intent = Intent(this, SplashActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
|
||||
val roomId = messageData["room_id"]
|
||||
if (roomId != null) {
|
||||
intent.putExtra(Constants.EXTRA_ROOM_ID, roomId.toLong())
|
||||
}
|
||||
|
||||
val socdocId = messageData["message_id"]
|
||||
if (socdocId != null) {
|
||||
intent.putExtra(Constants.EXTRA_MESSAGE_ID, socdocId.toLong())
|
||||
}
|
||||
|
||||
val audioContentId = messageData["content_id"]
|
||||
if (audioContentId != null) {
|
||||
intent.putExtra(Constants.EXTRA_CONTENT_ID, audioContentId.toLong())
|
||||
}
|
||||
|
||||
val pendingIntent =
|
||||
PendingIntent.getActivity(
|
||||
this,
|
||||
System.currentTimeMillis().toInt(),
|
||||
intent,
|
||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
val notificationBuilder = NotificationCompat.Builder(this, notificationChannelId)
|
||||
.setContentTitle(messageData["title"])
|
||||
.setContentText(messageData["message"])
|
||||
.setSound(defaultSoundUri)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent)
|
||||
|
||||
val bigTextStyle = NotificationCompat.BigTextStyle(notificationBuilder)
|
||||
bigTextStyle.bigText(messageData["message"])
|
||||
|
||||
notificationManager.notify(System.currentTimeMillis().toInt(), notificationBuilder.build())
|
||||
}
|
||||
}
|
|
@ -1,12 +1,19 @@
|
|||
package kr.co.vividnext.sodalive.main
|
||||
|
||||
import android.Manifest
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import com.gun0912.tedpermission.PermissionListener
|
||||
import com.gun0912.tedpermission.normal.TedPermission
|
||||
import com.orhanobut.logger.Logger
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.content.main.ContentMainFragment
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityMainBinding
|
||||
import kr.co.vividnext.sodalive.databinding.ItemMainTabBinding
|
||||
|
@ -27,8 +34,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setupBottomTabLayout()
|
||||
checkPermissions()
|
||||
pushTokenUpdate()
|
||||
|
||||
getMemberInfo()
|
||||
}
|
||||
|
@ -47,6 +54,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||
isNotifiedMessage
|
||||
)
|
||||
}
|
||||
|
||||
setupBottomTabLayout()
|
||||
}
|
||||
|
||||
private fun setupBottomTabLayout() {
|
||||
|
@ -196,6 +205,41 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||
fragmentTransaction.commitNow()
|
||||
}
|
||||
|
||||
private fun checkPermissions() {
|
||||
val permissions = mutableListOf(Manifest.permission.RECORD_AUDIO)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
permissions.add(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
|
||||
TedPermission.create()
|
||||
.setPermissionListener(object : PermissionListener {
|
||||
override fun onPermissionGranted() {
|
||||
}
|
||||
|
||||
override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {
|
||||
}
|
||||
})
|
||||
.setDeniedMessage(R.string.record_audio_permission_denied_message)
|
||||
.setPermissions(*permissions.toTypedArray())
|
||||
.check()
|
||||
}
|
||||
|
||||
private fun pushTokenUpdate() {
|
||||
FirebaseMessaging.getInstance().token.addOnCompleteListener {
|
||||
if (!it.isSuccessful) {
|
||||
Logger.v("Fetching FCM registration token failed", it.exception)
|
||||
return@addOnCompleteListener
|
||||
}
|
||||
|
||||
val pushToken = it.result
|
||||
if (pushToken != null) {
|
||||
SharedPreferenceManager.pushToken = pushToken
|
||||
viewModel.pushTokenUpdate(pushToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMemberInfo() {
|
||||
viewModel.getMemberInfo {
|
||||
notificationSettingsDialog.show(screenWidth)
|
||||
|
|
|
@ -60,6 +60,20 @@ class MainViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
fun pushTokenUpdate(pushToken: String) {
|
||||
val request = PushTokenUpdateRequest(
|
||||
pushToken = pushToken
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
userRepository
|
||||
.updatePushToken(request, "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({}, {})
|
||||
)
|
||||
}
|
||||
|
||||
fun getMemberInfo(showNotificationSettingsDialog: () -> Unit) {
|
||||
compositeDisposable.add(
|
||||
userRepository.getMemberInfo(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package kr.co.vividnext.sodalive.main
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class PushTokenUpdateRequest(
|
||||
@SerializedName("pushToken") val pushToken: String,
|
||||
@SerializedName("container") val container: String = "aos"
|
||||
)
|
|
@ -145,7 +145,7 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
|
|||
)
|
||||
} else if (audioContentIdString != null) {
|
||||
bundleOf(
|
||||
Constants.EXTRA_AUDIO_CONTENT_ID to audioContentIdString.toLong()
|
||||
Constants.EXTRA_CONTENT_ID to audioContentIdString.toLong()
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
|
@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.user
|
|||
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import kr.co.vividnext.sodalive.main.PushTokenUpdateRequest
|
||||
import kr.co.vividnext.sodalive.settings.notification.GetMemberInfoResponse
|
||||
import kr.co.vividnext.sodalive.settings.notification.UpdateNotificationSettingRequest
|
||||
import kr.co.vividnext.sodalive.user.find_password.ForgotPasswordRequest
|
||||
|
@ -14,6 +15,7 @@ import retrofit2.http.GET
|
|||
import retrofit2.http.Header
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.PUT
|
||||
import retrofit2.http.Part
|
||||
|
||||
interface UserApi {
|
||||
|
@ -40,4 +42,10 @@ interface UserApi {
|
|||
@Body request: UpdateNotificationSettingRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@PUT("/member/push-token/update")
|
||||
fun updatePushToken(
|
||||
@Body request: PushTokenUpdateRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package kr.co.vividnext.sodalive.user
|
||||
|
||||
import kr.co.vividnext.sodalive.main.PushTokenUpdateRequest
|
||||
import kr.co.vividnext.sodalive.settings.notification.UpdateNotificationSettingRequest
|
||||
import kr.co.vividnext.sodalive.user.find_password.ForgotPasswordRequest
|
||||
import kr.co.vividnext.sodalive.user.login.LoginRequest
|
||||
|
@ -21,5 +22,10 @@ class UserRepository(private val userApi: UserApi) {
|
|||
token: String
|
||||
) = userApi.updateNotificationSettings(request, authHeader = token)
|
||||
|
||||
fun updatePushToken(
|
||||
request: PushTokenUpdateRequest,
|
||||
token: String
|
||||
) = userApi.updatePushToken(request, authHeader = token)
|
||||
|
||||
fun getMemberInfo(token: String) = userApi.getMemberInfo(authHeader = token)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
<resources>
|
||||
<string name="app_name">소다라이브</string>
|
||||
<string name="picker_gallery">갤러리</string>
|
||||
<string name="picker_camera">카메라</string>
|
||||
<string name="picker_select">선택</string>
|
||||
<string name="picker_media_permissions_hint">갤러리 접근을 위해 미디어 권한을 허용해야 합니다.</string>
|
||||
<string name="picker_empty_media">미디어 라이브러리가 비어있습니다.</string>
|
||||
<string name="picker_allow">허용</string>
|
||||
<string name="picker_select_photo">사진선택</string>
|
||||
<string name="picker_no_camera">사용할 수 있는 카메라 앱이 없습니다.</string>
|
||||
<string name="default_notification_channel_id">soda_fcm_default_channel</string>
|
||||
<string name="record_audio_permission_denied_message"><![CDATA[권한을 거부하시면 라이브 참여를 하실 수 없습니다.\n\n[설정]->[권한]에서 권한을 허용해 주시기 바랍니다.]]></string>
|
||||
<string name="read_storage_permission_denied_message"><![CDATA[권한을 거부하시면 콘텐츠를 업로드 하실 수 없습니다.\n\n[설정]->[권한]에서 권한을 허용해 주시기 바랍니다.]]></string>
|
||||
<string name="retry">다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다.</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue