Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat : FCM 푸쉬 알림 구현 #219

Merged
merged 12 commits into from
Apr 2, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,29 @@ package com.dongyang.android.youdongknowme.service
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.TaskStackBuilder
import android.content.Context
import android.content.Intent
import android.media.RingtoneManager
import android.os.Build
import androidx.core.app.NotificationCompat
import com.dongyang.android.youdongknowme.data.local.SharedPreference
import com.dongyang.android.youdongknowme.ui.view.detail.DetailActivity
import com.dongyang.android.youdongknowme.ui.view.main.MainActivity
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class FCMService : FirebaseMessagingService() {

override fun onMessageReceived(remoteMessage: RemoteMessage) {
val title = remoteMessage.notification?.title ?: "기본 제목"
val message = remoteMessage.notification?.body ?: "기본 메시지"
override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)

val title = message.notification?.title ?: "기본 제목"
val messageBody = message.notification?.body ?: "기본 메시지"
val url = message.data["url"] ?: ""

// 알림 채널 ID
val channelId = "your_channel_id"
val channelId = "DMforU"

// NotificationManager 인스턴스 생성
val notificationManager =
Expand All @@ -36,22 +41,39 @@ class FCMService : FirebaseMessagingService() {
notificationManager.createNotificationChannel(channel)
}

// Intent 및 PendingIntent 생성
val intent = Intent(this, MainActivity::class.java).apply {
// MainActivity를 시작하는 Intent 생성
val mainIntent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
}
val pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)

// DetailActivity를 열기 위한 Intent 생성
val detailIntent = if (!url.isNullOrEmpty()) {
DetailActivity.newIntent(this, url)
} else {
null // URL이 없는 경우에는 null 할당
}

// PendingIntent 생성
val pendingIntent = if (detailIntent != null) {
TaskStackBuilder.create(this).run {
addNextIntent(mainIntent)
addNextIntentWithParentStack(detailIntent) // DetailActivity를 부모 스택으로 추가
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
} else {
PendingIntent.getActivity(
this,
0,
mainIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
}

// 알림 생성
val builder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(com.dongyang.android.youdongknowme.R.mipmap.ic_logo) // 알림 아이콘 설정
.setContentTitle(title) // 알림 제목
.setContentText(message) // 알림 내용
.setContentText(messageBody) // 알림 내용
.setAutoCancel(true) // 터치 시 자동으로 삭제되도록 설정
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) // 알림 소리 설정
.setVibrate(longArrayOf(0, 1000, 500, 1000)) // 진동 패턴 설정
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,25 @@ package com.dongyang.android.youdongknowme.standard.util
fun mapKeywordEnglishToKorean(english: String): String {
return when (english) {
"exam" -> "시험"
"course" -> "수강"
"lecture" -> "특강"
"season" -> "계절학기"
"signup" -> "수강"
"speciallecture" -> "특강"
"seasonalsemester" -> "계절학기"
"leaveofabsence" -> "휴학"
"returntoschool" -> "복학"
"graduate" -> "졸업"
"switchmajors" -> "전과"
"givingupthesemester" -> "학기포기"
"scholarship" -> "장학"
"tuition" -> "등록"
"leave" -> "휴학"
"return" -> "복학"
"graduation" -> "졸업"
"transfer" -> "전과"
"drop" -> "학기포기"
"recruitment" -> "채용"
"nationalscholarship" -> "국가장학"
"registration" -> "등록"
"employment" -> "채용"
"contest" -> "공모전"
"field" -> "현장실습"
"competition" -> "대회"
"service" -> "봉사"
"fieldtraining" -> "현장실습"
"volunteer" -> "봉사"
"dormitory" -> "기숙사"
"corona" -> "코로나19"
"club" -> "동아리"
else -> throw IllegalArgumentException("올바른 타입이 아닙니다.")
}
}

fun mapDepartmentCodeToKorean(code: Int): String {
return when (code) {
CODE.SCHOOL_CODE -> "학교"
CODE.MECHANICAL_ENGINE_CODE -> "기계공학과"
CODE.MECHANICAL_DESIGN_CODE -> "기계설계공학과"
CODE.AUTOMATION_ENGINE_CODE -> "자동화공학과"
CODE.ROBOT_ENGINE_CODE -> "로봇공학과"
CODE.COMPUTER_SOFTWARE_ENGINE_CODE -> "컴퓨터소프트웨어공학과"
CODE.COMPUTER_INFO_ENGINE_CODE -> "컴퓨터정보공학과"
CODE.ARTIFICIAL_ENGINE_CODE -> "인공지능소프트웨어공학과"
CODE.ELECTRICAL_ENGINE_CODE -> "전기공학과"
CODE.INFO_ELECTRONIC_ENGINE_CODE -> "정보전자공학과"
CODE.SEMICONDUCTOR_ENGINE_CODE -> "반도체전자공학과"
CODE.INFO_COMMUNICATION_ENGINE_CODE -> "정보통신공학과"
CODE.BIOCHEMICAL_ENGINE_CODE -> "생명화학공학과"
CODE.BIO_CONVERGENCE_ENGINE_CODE -> "바이오융합공학과"
CODE.ARCHITECTURE_CODE -> "건축과"
CODE.INTERIOR_DESIGN_CODE -> "실내건축디자인과"
CODE.VISUAL_DESIGN_CODE -> "시각디자인과"
CODE.BUSINESS_ADMINISTRATION_CODE -> "경영학과"
CODE.TAX_ACCOUNTING_CODE -> "세무회계학과"
CODE.DISTRIBUTION_MARKETING_CODE -> "유통마케팅학과"
CODE.HOTEL_TOURISM_CODE -> "호텔관광학과"
CODE.MANAGEMENT_INFORMATION_CODE -> "경영정보학과"
CODE.BIG_DATA_MANAGEMENT_CODE -> "빅데이터경영과"
"group" -> "동아리"
"studentcouncil" -> "학생회"
else -> throw IllegalArgumentException("올바른 타입이 아닙니다.")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.dongyang.android.youdongknowme.standard.base.BaseActivity
import com.dongyang.android.youdongknowme.ui.adapter.DepartAdapter
import com.dongyang.android.youdongknowme.ui.view.main.MainActivity
import org.koin.androidx.viewmodel.ext.android.viewModel
import timber.log.Timber


class DepartActivity : BaseActivity<ActivityDepartBinding, DepartViewModel>(), DepartClickListener {
Expand Down Expand Up @@ -64,6 +65,7 @@ class DepartActivity : BaseActivity<ActivityDepartBinding, DepartViewModel>(), D
private fun getDepart(items: ArrayList<String>) {
return binding.btnDepartComplete.setOnClickListener {
viewModel.setDepartment(items[viewModel.selectDepartPosition.value ?: 0])
setResult(RESULT_OK)
finish()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class KeywordActivity : BaseActivity<ActivityKeywordBinding, KeywordViewModel>()
viewModel.getLocalKeywordList()

binding.btnKeywordComplete.setOnClickListener {
viewModel.subscribeCheckedKeyword()
setResult(RESULT_OK)
finish()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import com.dongyang.android.youdongknowme.data.local.SharedPreference
import com.dongyang.android.youdongknowme.databinding.ActivityMainBinding
import com.dongyang.android.youdongknowme.standard.base.BaseActivity
import com.dongyang.android.youdongknowme.ui.view.util.KeepStateNavigator
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.messaging.FirebaseMessaging
import org.koin.androidx.viewmodel.ext.android.viewModel
import timber.log.Timber

/* 메인 액티비티 */
class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
Expand All @@ -36,23 +36,28 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
binding.mainNvBottom.setupWithNavController(navController)

viewModel.checkFirstLaunch()
}

if (viewModel.isFirstLaunch.value == true) {
getFcmToken()
override fun initDataBinding() {
viewModel.isFirstLaunch.observe(this) { boolean ->
if (boolean) getFcmToken()
}
}

override fun initDataBinding() = Unit
override fun initAfterBinding() = Unit

private fun getFcmToken() {
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
viewModel.setFCMToken(task.result)
viewModel.setInitToken()
viewModel.setFCMToken(task.result).run { viewModel.setInitToken() }
Timber.d("first ${task.result}")
} else {
return@addOnCompleteListener
}
val token = task.result
SharedPreference.setFcmToken(token)

Timber.d("token : ${token}")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
import com.dongyang.android.youdongknowme.standard.network.NetworkResult
import com.dongyang.android.youdongknowme.ui.view.util.Event
import kotlinx.coroutines.launch
import timber.log.Timber

class MainViewModel(private val mainRepository: MainRepository) : BaseViewModel() {
private val _errorState: MutableLiveData<Event<Int>> = MutableLiveData()
Expand Down Expand Up @@ -45,7 +46,7 @@ class MainViewModel(private val mainRepository: MainRepository) : BaseViewModel(

fun setFCMToken(token: String){
mainRepository.setFCMToken(token)
_FCMToken.postValue(token)
_FCMToken.value = token
}

private fun getUserDepart(){
Expand All @@ -69,6 +70,7 @@ class MainViewModel(private val mainRepository: MainRepository) : BaseViewModel(
)
)) {
is NetworkResult.Success -> {
Timber.d("first ${FCMToken.value.toString()}")
mainRepository.setIsFirstLaunch(false)
_isFirstLaunch.postValue(false)
_isLoading.postValue(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,29 @@ class SettingFragment : BaseFragment<FragmentSettingBinding, SettingViewModel>()
override val layoutResourceId: Int = R.layout.fragment_setting
override val viewModel: SettingViewModel by viewModel()

private lateinit var resultLauncher: ActivityResultLauncher<Intent>
private lateinit var resultLauncherKeyword: ActivityResultLauncher<Intent>
private lateinit var resultResultDepartment: ActivityResultLauncher<Intent>

private var topics: List<String> = emptyList()
private var department: String = ""

override fun initStartView() {
binding.tvSettingAppVersion.text = getAppVersion()
setResultKeyword()
setResultDepartment()
}

override fun initDataBinding() {

viewModel.myDepartment.observe(viewLifecycleOwner) { myDepartment ->
binding.tvSettingDepartment.text = myDepartment
department = myDepartment
viewModel.updateUserDepartment(department)
}

viewModel.myTopics.observe(viewLifecycleOwner) { myTopics ->
topics = topics
topics = myTopics
viewModel.updateUserTopic(topics)
}

viewModel.isAccessUniversityAlarm.observe(viewLifecycleOwner) { isChecked ->
Expand All @@ -54,36 +61,39 @@ class SettingFragment : BaseFragment<FragmentSettingBinding, SettingViewModel>()

binding.switchSettingUniversityAlarm.setOnCheckedChangeListener { compoundButton, _ ->
if (compoundButton.isChecked) {
viewModel.updateUserTopic(topics)
if (topics.isNotEmpty()) {
viewModel.updateUserTopic(topics)
}
} else {
viewModel.removeUserTopic()
}
}

binding.switchSettingDepartmentAlarm.setOnCheckedChangeListener { compoundButton, _ ->
if (compoundButton.isChecked) {
viewModel.updateUserDepartment()
if (department.isNotEmpty()) {
viewModel.updateUserDepartment(department)
}
} else {
viewModel.removeUserDepartment()
}
}

binding.btnSettingEditKeyword.setOnClickListener {
val intent = Intent(requireActivity(), KeywordActivity::class.java)
resultLauncher.launch(intent)
resultLauncherKeyword.launch(intent)
}

binding.btnSettingEditDepartment.setOnClickListener {
val intent = Intent(requireActivity(), DepartActivity::class.java)
startActivity(intent)
resultResultDepartment.launch(intent)
}

binding.btnSettingAppHelp.setOnClickListener {
val intent =
Intent(
Intent.ACTION_VIEW,
Uri.parse("https://docs.google.com/forms/d/e/1FAIpQLSeRTKalenelmffTbCZeK4mqmQg0palobghkXSoie1FlmV22ZQ/viewform")
)
val intent = Intent(
Intent.ACTION_VIEW,
Uri.parse("https://docs.google.com/forms/d/e/1FAIpQLSeRTKalenelmffTbCZeK4mqmQg0palobghkXSoie1FlmV22ZQ/viewform")
)
startActivity(intent)
}

Expand All @@ -108,11 +118,21 @@ class SettingFragment : BaseFragment<FragmentSettingBinding, SettingViewModel>()
}

private fun setResultKeyword() {
resultLauncher =
resultLauncherKeyword =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
viewModel.getUserTopic()
viewModel.updateUserTopic(topics)
viewModel.getUserTopic().run { viewModel.updateUserTopic(topics) }
binding.switchSettingUniversityAlarm.isChecked = true
}
}
}

private fun setResultDepartment() {
resultResultDepartment =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
viewModel.getUserDepartment()
binding.switchSettingDepartmentAlarm.isChecked = true
}
}
}
Expand Down
Loading
Loading