-
Notifications
You must be signed in to change notification settings - Fork 1
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] 코스 상세 페이지 / Firebase 동적 링크로 코스 공유 구현 #326
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,20 @@ | ||
package com.runnect.runnect.presentation.detail | ||
|
||
import android.app.Activity | ||
import android.content.ActivityNotFoundException | ||
import android.content.Intent | ||
import android.graphics.Rect | ||
import android.net.Uri | ||
import android.os.Bundle | ||
import android.view.Gravity | ||
import android.view.MotionEvent | ||
import android.view.View | ||
import android.widget.EditText | ||
import android.widget.Toast | ||
import androidx.activity.OnBackPressedCallback | ||
import androidx.activity.viewModels | ||
import androidx.core.view.isVisible | ||
import coil.load | ||
import com.gun0912.tedpermission.provider.TedPermissionProvider.context | ||
import com.kakao.sdk.common.util.KakaoCustomTabsClient | ||
import com.kakao.sdk.link.LinkClient | ||
import com.kakao.sdk.link.WebSharerClient | ||
import com.kakao.sdk.template.model.Button | ||
import com.kakao.sdk.template.model.Content | ||
import com.kakao.sdk.template.model.FeedTemplate | ||
import com.kakao.sdk.template.model.Link | ||
import com.google.firebase.dynamiclinks.DynamicLink | ||
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks | ||
import com.naver.maps.geometry.LatLng | ||
import com.runnect.runnect.R | ||
import com.runnect.runnect.binding.BindingActivity | ||
|
@@ -90,33 +83,44 @@ class CourseDetailActivity : | |
|
||
Analytics.logClickedItemEvent(VIEW_COURSE_DETAIL) | ||
|
||
initIntentExtraData() | ||
updatePublicCourseIdFromDeepLink() | ||
getCourseDetail() | ||
|
||
addListener() | ||
addObserver() | ||
registerBackPressedCallback() | ||
updatePublicCourseIdFromDynamicLink { dynamicLinkHandled -> | ||
if (!dynamicLinkHandled) { | ||
initIntentExtraData() | ||
} | ||
addListener() | ||
addObserver() | ||
registerBackPressedCallback() | ||
getCourseDetail() | ||
} | ||
} | ||
|
||
private fun initIntentExtraData() { | ||
intent.getCompatibleSerializableExtra<CourseDetailRootScreen>(EXTRA_ROOT_SCREEN)?.let { | ||
rootScreen = it | ||
} | ||
publicCourseId = intent.getIntExtra(EXTRA_PUBLIC_COURSE_ID, 0) | ||
} | ||
|
||
private fun updatePublicCourseIdFromDeepLink() { | ||
// 딥링크를 통해 열린 경우 | ||
if (Intent.ACTION_VIEW == intent.action) { | ||
isFromDeepLink = true | ||
val uri = intent.data | ||
if (uri != null) { | ||
// 여기서 androidExecutionParams 값들을 받아와 어떠한 상세 페이지를 띄울지 결정할 수 있음. | ||
publicCourseId = uri.getQueryParameter("publicCourseId")!!.toInt() | ||
Timber.tag("deeplink-publicCourseId").d("$publicCourseId") | ||
publicCourseId = intent.getIntExtra(EXTRA_PUBLIC_COURSE_ID, -1) | ||
Timber.tag("intent-publicCourseId").d("$publicCourseId") | ||
} | ||
|
||
private fun updatePublicCourseIdFromDynamicLink(completion: (Boolean) -> Unit) { | ||
FirebaseDynamicLinks.getInstance().getDynamicLink(intent) | ||
.addOnSuccessListener(this) { pendingDynamicLinkData -> | ||
val deepLink: Uri? = pendingDynamicLinkData?.link | ||
if (deepLink != null) { | ||
isFromDeepLink = true | ||
publicCourseId = deepLink.getQueryParameter("courseId")?.toInt() ?: -1 | ||
if (publicCourseId != -1) { | ||
Timber.tag("deeplink-publicCourseId").d("$publicCourseId") | ||
completion(true) | ||
return@addOnSuccessListener | ||
} | ||
} | ||
completion(false) | ||
} | ||
.addOnFailureListener(this) { e -> | ||
Timber.e("getDynamicLink:onFailure", e) | ||
completion(false) | ||
} | ||
} | ||
} | ||
|
||
private fun getCourseDetail() { | ||
|
@@ -163,7 +167,7 @@ class CourseDetailActivity : | |
intent?.let { newIntent -> | ||
newIntent.getCompatibleSerializableExtra<CourseDetailRootScreen>(EXTRA_ROOT_SCREEN) | ||
?.let { rootScreen = it } | ||
publicCourseId = newIntent.getIntExtra(EXTRA_PUBLIC_COURSE_ID, 0) | ||
publicCourseId = newIntent.getIntExtra(EXTRA_PUBLIC_COURSE_ID, -1) | ||
getCourseDetail() | ||
} | ||
} | ||
|
@@ -238,9 +242,42 @@ class CourseDetailActivity : | |
} | ||
} | ||
|
||
private fun sendFirebaseDynamicLink(title: String, desc: String, image: String) { | ||
val link = "https://rnnt.page.link/?courseId=$publicCourseId" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 문자열 리소스 사용하거나 companion 객체 안에 상수화 시켜주는 게 좋을 거 같습니다! (오타 발생 가능성) |
||
|
||
FirebaseDynamicLinks.getInstance().createDynamicLink() | ||
.setLink(Uri.parse(link)) | ||
.setDomainUriPrefix("https://rnnt.page.link") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기 문자열도 상수화 시켜주면 좋을 거 같아요! |
||
.setAndroidParameters(DynamicLink.AndroidParameters.Builder().build()) | ||
.setIosParameters(DynamicLink.IosParameters.Builder("com.runnect.Runnect-iOS").build()) | ||
.setSocialMetaTagParameters( | ||
DynamicLink.SocialMetaTagParameters.Builder() | ||
.setTitle(title) | ||
.setDescription(desc) | ||
.setImageUrl(Uri.parse(image)) | ||
.build() | ||
) | ||
.buildShortDynamicLink() | ||
.addOnSuccessListener { result -> | ||
val shortLink = result.shortLink | ||
shareLink(shortLink.toString()) | ||
} | ||
.addOnFailureListener { | ||
it.printStackTrace() | ||
} | ||
} | ||
|
||
private fun shareLink(url: String) { | ||
val intent = Intent(Intent.ACTION_SEND).apply { | ||
type = "text/plain" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기도 상수화 시켜주면 더욱 좋겠네요 :) |
||
putExtra(Intent.EXTRA_TEXT, url) | ||
} | ||
startActivity(Intent.createChooser(intent, "Share Link")) | ||
} | ||
|
||
private fun initShareButtonClickListener() { | ||
binding.btnShare.setOnClickListener { | ||
sendKakaoLink( | ||
sendFirebaseDynamicLink( | ||
title = courseDetail.title, | ||
desc = courseDetail.description, | ||
image = courseDetail.image | ||
|
@@ -255,71 +292,6 @@ class CourseDetailActivity : | |
} | ||
} | ||
|
||
// todo: 함수를 더 작게 분리하는 게 좋을 거 같아요! @우남 | ||
private fun sendKakaoLink(title: String, desc: String, image: String) { | ||
// 메시지 템플릿 만들기 (피드형) | ||
val defaultFeed = FeedTemplate( | ||
content = Content( | ||
title = title, | ||
description = desc, | ||
imageUrl = image, | ||
link = Link( | ||
mobileWebUrl = "https://play.google.com/store/apps/details?id=com.runnect.runnect" | ||
) | ||
), | ||
buttons = listOf( | ||
Button( | ||
"자세히 보기", | ||
Link( | ||
//이 부분을 사용해서 어떤 상세페이지를 띄울지 결정할수 있다 | ||
androidExecutionParams = mapOf( | ||
"publicCourseId" to publicCourseId.toString(), | ||
) | ||
), | ||
) | ||
) | ||
) | ||
|
||
// 피드 메시지 보내기 | ||
if (context?.let { LinkClient.instance.isKakaoLinkAvailable(it) } == true) { | ||
// 카카오톡으로 카카오링크 공유 가능 | ||
context?.let { | ||
LinkClient.instance.defaultTemplate(it, defaultFeed) { linkResult, error -> | ||
if (error != null) { | ||
Timber.tag("kakao_link").d("카카오링크 보내기 실패: $error") | ||
} else if (linkResult != null) { | ||
Timber.tag("kakao_link").d("카카오링크 보내기 성공: ${linkResult.intent}") | ||
|
||
startActivity(linkResult.intent) //카카오톡이 깔려있을 경우 카카오톡으로 넘기기 | ||
|
||
// 카카오링크 보내기에 성공했지만 아래 경고 메시지가 존재할 경우 일부 컨텐츠가 정상 동작하지 않음 | ||
Timber.tag("kakao_link").d("Warning Msg: ${linkResult.warningMsg}") | ||
Timber.tag("kakao_link").d("Argument Msg: ${linkResult.argumentMsg}") | ||
} | ||
} | ||
} | ||
} else { // 카카오톡 미설치: 웹 공유 사용 권장 | ||
// 웹 공유 예시 코드 | ||
val sharerUrl = WebSharerClient.instance.defaultTemplateUri(defaultFeed) | ||
|
||
// 1. CustomTabs으로 Chrome 브라우저 열기 | ||
try { | ||
context?.let { KakaoCustomTabsClient.openWithDefault(it, sharerUrl) } | ||
} catch (e: UnsupportedOperationException) { | ||
// Chrome 브라우저가 없을 때 | ||
Toast.makeText(context, "chrome 또는 인터넷 브라우저를 설치해주세요", Toast.LENGTH_SHORT).show() | ||
} | ||
|
||
// 2. CustomTabs으로 디바이스 기본 브라우저 열기 | ||
try { | ||
context?.let { KakaoCustomTabsClient.open(it, sharerUrl) } | ||
} catch (e: ActivityNotFoundException) { | ||
// 인터넷 브라우저가 없을 때 | ||
Toast.makeText(context, "chrome 또는 인터넷 브라우저를 설치해주세요", Toast.LENGTH_SHORT).show() | ||
} | ||
} | ||
} | ||
|
||
private fun initStartRunButtonClickListener() { | ||
binding.btnCourseDetailStartRun.setOnClickListener { | ||
if (isVisitorMode) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고차함수를 이렇게 활용할 수 있군요! 가독성 향상된 거 같아서 좋습니다!