Skip to content

Commit c9d1380

Browse files
committed
Merge branch 'feat/link-sharing' into 'master'
Možnost pozvat uživatele odesláním odkazu Closes #35 See merge request fmasa/pv239-project!63
2 parents 7b2fe3e + fb2c2fd commit c9d1380

File tree

14 files changed

+246
-104
lines changed

14 files changed

+246
-104
lines changed

app/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ android {
5555
applicationIdSuffix ".debug"
5656
resValue "string", "app_name", "[Debug] WFRP Master"
5757
resValue "string", "character_ad_unit_id", "ca-app-pub-3940256099942544/6300978111"
58+
manifestPlaceholders = [analytics_deactivated: "true"]
5859
}
5960

6061
release {
@@ -63,6 +64,7 @@ android {
6364
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
6465
resValue "string", "app_name", "WFRP Master"
6566
resValue "string", "character_ad_unit_id", "ca-app-pub-8647604386686373/9919978313"
67+
manifestPlaceholders = [analytics_deactivated: "false"]
6668
}
6769
}
6870

@@ -107,6 +109,7 @@ dependencies {
107109
implementation 'com.google.firebase:firebase-firestore-ktx:21.4.3'
108110
implementation 'com.google.firebase:firebase-analytics-ktx:17.4.3'
109111
implementation 'com.google.firebase:firebase-crashlytics:17.0.1'
112+
implementation 'com.google.firebase:firebase-dynamic-links-ktx:19.1.0'
110113

111114
implementation 'com.getbase:floatingactionbutton:1.10.1'
112115

app/google-services.json

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
}
3434
]
3535
}
36-
}
36+
},
37+
"admob_app_id": "ca-app-pub-8647604386686373~4029550903"
3738
},
3839
{
3940
"client_info": {
@@ -63,43 +64,6 @@
6364
]
6465
}
6566
}
66-
},
67-
{
68-
"client_info": {
69-
"mobilesdk_app_id": "1:723151893906:android:b001abe54ab88730c53d4b",
70-
"android_client_info": {
71-
"package_name": "cz.muni.fi.rpg"
72-
}
73-
},
74-
"oauth_client": [
75-
{
76-
"client_id": "723151893906-q1ij6ocfq9bl7ssomm6d813rm3drfp9h.apps.googleusercontent.com",
77-
"client_type": 1,
78-
"android_info": {
79-
"package_name": "cz.muni.fi.rpg",
80-
"certificate_hash": "be2015c91edcc5cdc7cea224ab871a06d645937a"
81-
}
82-
},
83-
{
84-
"client_id": "723151893906-jcpa54h9uvdk614pj82ap53m4d4jmcd4.apps.googleusercontent.com",
85-
"client_type": 3
86-
}
87-
],
88-
"api_key": [
89-
{
90-
"current_key": "AIzaSyDO4Y4wWcY4HdYcsp8zcLMpMjwUJ_9q3Fw"
91-
}
92-
],
93-
"services": {
94-
"appinvite_service": {
95-
"other_platform_oauth_client": [
96-
{
97-
"client_id": "723151893906-jcpa54h9uvdk614pj82ap53m4d4jmcd4.apps.googleusercontent.com",
98-
"client_type": 3
99-
}
100-
]
101-
}
102-
}
10367
}
10468
],
10569
"configuration_version": "1"

app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
android:theme="@style/AppTheme">
1515
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID"
1616
android:value="ca-app-pub-8647604386686373~4029550903"/>
17+
<meta-data
18+
android:name="firebase_analytics_collection_deactivated"
19+
android:value="${analytics_deactivated}" />
1720
<activity
1821
android:name=".ui.MainActivity"
1922
android:theme="@style/AppTheme.NoActionBar" />
@@ -29,6 +32,15 @@
2932
<activity
3033
android:name=".ui.joinParty.JoinPartyActivity"
3134
android:label="@string/title_joinParty" />
35+
<activity android:name=".ui.joinParty.InvitationLinkActivity"
36+
android:label="@string/title_joinParty">
37+
<intent-filter>
38+
<action android:name="android.intent.action.VIEW"/>
39+
<category android:name="android.intent.category.DEFAULT"/>
40+
<category android:name="android.intent.category.BROWSABLE"/>
41+
<data android:host="wfrp.page.link" android:scheme="https"/>
42+
</intent-filter>
43+
</activity>
3244
</application>
3345

3446
</manifest>
Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,39 @@
11
package cz.muni.fi.rpg.ui
22

33
import android.content.Intent
4-
import android.util.Log
54
import android.widget.Toast
65
import androidx.appcompat.app.AppCompatActivity
7-
import com.google.firebase.auth.FirebaseAuth
86
import cz.muni.fi.rpg.R
9-
import org.koin.android.ext.android.inject
7+
import cz.muni.fi.rpg.viewModels.AuthenticationViewModel
8+
import kotlinx.coroutines.CoroutineScope
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.launch
11+
import kotlinx.coroutines.withContext
12+
import org.koin.android.viewmodel.ext.android.viewModel
1013

11-
class StartupActivity : AppCompatActivity(R.layout.activity_startup) {
12-
private val auth: FirebaseAuth by inject()
14+
class StartupActivity : AppCompatActivity(R.layout.activity_startup),
15+
CoroutineScope by CoroutineScope(Dispatchers.Default) {
16+
17+
private val viewModel: AuthenticationViewModel by viewModel()
1318

1419
override fun onStart() {
1520
super.onStart()
1621

17-
val currentUser = auth.currentUser
18-
19-
if (currentUser != null) {
20-
showPartyList()
21-
return
22-
}
23-
24-
auth.signInAnonymously().addOnCompleteListener(this) { task ->
25-
if (task.isSuccessful) {
26-
Log.d(null, "User has signed in successfully")
27-
22+
launch {
23+
if (viewModel.isAuthenticated() || viewModel.authenticateAnonymously()) {
2824
showPartyList()
2925
} else {
30-
Log.e(null, "Anonymous sign-in has failed", task.exception)
31-
Toast.makeText(baseContext, "Authentication failed.", Toast.LENGTH_SHORT).show()
26+
withContext(Dispatchers.Main) {
27+
Toast.makeText(baseContext, "Authentication failed.", Toast.LENGTH_SHORT).show()
28+
}
3229
}
3330
}
3431
}
3532

36-
private fun showPartyList() {
37-
startActivity(Intent(this, MainActivity::class.java))
38-
finish()
33+
private suspend fun showPartyList() {
34+
withContext(Dispatchers.Main) {
35+
startActivity(Intent(this@StartupActivity, MainActivity::class.java))
36+
finish()
37+
}
3938
}
4039
}

app/src/main/java/cz/muni/fi/rpg/ui/gameMaster/GameMasterFragment.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class GameMasterFragment(
8787
}
8888

8989
private fun showQrCode() {
90-
QrCodeDialog(invitation, jsonMapper)
91-
.show(requireActivity().supportFragmentManager, QrCodeDialog::class.simpleName)
90+
InvitationDialog(invitation, jsonMapper)
91+
.show(requireActivity().supportFragmentManager, InvitationDialog::class.simpleName)
9292
}
9393
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package cz.muni.fi.rpg.ui.gameMaster
2+
3+
import android.app.Dialog
4+
import android.content.Intent
5+
import android.net.Uri
6+
import android.os.Bundle
7+
import android.util.Log
8+
import android.view.View
9+
import androidx.appcompat.app.AlertDialog
10+
import androidx.fragment.app.DialogFragment
11+
import com.fasterxml.jackson.databind.json.JsonMapper
12+
import com.google.firebase.dynamiclinks.ktx.dynamicLinks
13+
import com.google.firebase.dynamiclinks.ktx.shortLinkAsync
14+
import com.google.firebase.ktx.Firebase
15+
import cz.muni.fi.rpg.R
16+
import cz.muni.fi.rpg.model.domain.party.Invitation
17+
import kotlinx.android.synthetic.main.dialog_invitation.view.*
18+
import kotlinx.coroutines.CoroutineScope
19+
import kotlinx.coroutines.Dispatchers
20+
import kotlinx.coroutines.launch
21+
import kotlinx.coroutines.tasks.await
22+
import kotlinx.coroutines.withContext
23+
24+
class InvitationDialog(
25+
private val invitation: Invitation,
26+
private val jsonMapper: JsonMapper
27+
) : DialogFragment(), CoroutineScope by CoroutineScope(Dispatchers.Default) {
28+
29+
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
30+
val view = requireActivity().layoutInflater.inflate(R.layout.dialog_invitation, null)
31+
32+
val dialog = AlertDialog.Builder(requireContext())
33+
.setView(view)
34+
.create()
35+
36+
val codeGenerating = launch {
37+
val jsonInvitation = withContext(Dispatchers.IO) {
38+
jsonMapper.writeValueAsString(invitation)
39+
}
40+
41+
launch(Dispatchers.Main) { view.partyInviteQrCode.drawCode(jsonInvitation) }
42+
43+
initializeButton(view, invitation, jsonInvitation)
44+
}
45+
46+
dialog.setOnDismissListener { codeGenerating.cancel() }
47+
48+
return dialog
49+
}
50+
51+
private suspend fun initializeButton(
52+
view: View,
53+
invitation: Invitation,
54+
jsonInvitation: String
55+
) {
56+
val link = Firebase.dynamicLinks.shortLinkAsync {
57+
link = Uri.parse("https://play.google.com/store/apps/details?id=cz.frantisekmasa.dnd&invitation=$jsonInvitation")
58+
domainUriPrefix = "https://wfrp.page.link"
59+
}.await()
60+
61+
Log.d(tag, "Invitation link was generated: ${link.shortLink}")
62+
63+
withContext(Dispatchers.Main) {
64+
view.shareButton.setOnClickListener {
65+
val sendIntent = Intent().apply {
66+
action = Intent.ACTION_SEND
67+
putExtra(
68+
Intent.EXTRA_TEXT,
69+
"Join ${invitation.partyName} using this link: ${link.shortLink}"
70+
)
71+
type = "text/plain"
72+
}
73+
74+
startActivity(Intent.createChooser(sendIntent, "Send link to your friends"))
75+
}
76+
view.shareButton.isEnabled = true
77+
}
78+
}
79+
}

app/src/main/java/cz/muni/fi/rpg/ui/gameMaster/QrCodeDialog.kt

Lines changed: 0 additions & 39 deletions
This file was deleted.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package cz.muni.fi.rpg.ui.joinParty
2+
3+
import android.content.Intent
4+
import android.util.Log
5+
import android.widget.Toast
6+
import androidx.appcompat.app.AppCompatActivity
7+
import com.fasterxml.jackson.databind.json.JsonMapper
8+
import com.google.firebase.dynamiclinks.ktx.dynamicLinks
9+
import com.google.firebase.ktx.Firebase
10+
import cz.muni.fi.rpg.R
11+
import cz.muni.fi.rpg.model.domain.invitation.InvitationProcessor
12+
import cz.muni.fi.rpg.model.domain.party.Invitation
13+
import cz.muni.fi.rpg.ui.MainActivity
14+
import cz.muni.fi.rpg.viewModels.AuthenticationViewModel
15+
import kotlinx.coroutines.CoroutineScope
16+
import kotlinx.coroutines.Dispatchers
17+
import kotlinx.coroutines.launch
18+
import kotlinx.coroutines.tasks.await
19+
import kotlinx.coroutines.withContext
20+
import org.koin.android.ext.android.inject
21+
22+
class InvitationLinkActivity : AppCompatActivity(R.layout.activity_invitation_link),
23+
CoroutineScope by CoroutineScope(Dispatchers.Default) {
24+
companion object {
25+
const val tag = "InvitationLinkActivity"
26+
}
27+
28+
private val auth: AuthenticationViewModel by inject()
29+
private val jsonMapper: JsonMapper by inject()
30+
private val invitationProcessor: InvitationProcessor by inject()
31+
32+
override fun onStart() {
33+
super.onStart()
34+
35+
launch {
36+
authenticate()
37+
acceptDynamicLinks()
38+
}
39+
}
40+
41+
private suspend fun authenticate(): Boolean {
42+
return auth.isAuthenticated() || auth.authenticateAnonymously()
43+
}
44+
45+
private suspend fun acceptDynamicLinks() {
46+
try {
47+
val link = Firebase.dynamicLinks.getDynamicLink(intent).await()?.link ?: return
48+
val invitationJson = link.getQueryParameter("invitation")
49+
50+
if (invitationJson == null) {
51+
Log.d(tag, "Dynamic link URI does not have 'invitation' query parameter")
52+
53+
withContext(Dispatchers.Main) { openPartyList() }
54+
return
55+
}
56+
57+
@Suppress("BlockingMethodInNonBlockingContext")
58+
val invitation = jsonMapper.readValue(invitationJson, Invitation::class.java)
59+
60+
withContext(Dispatchers.Main) {
61+
JoinPartyDialog(auth.getUserId(), invitation, invitationProcessor)
62+
.setOnErrorListener { openPartyList() }
63+
.setOnSuccessListener { openPartyList() }
64+
.setOnDismissListener { openPartyList() }
65+
.show(supportFragmentManager, "JoinPartyDialog")
66+
}
67+
} catch (e: Throwable) {
68+
Log.w("MainActivity", "Could not process Dynamic Link data", e)
69+
withContext(Dispatchers.Main) {
70+
Toast.makeText(applicationContext, "Invalid link", Toast.LENGTH_SHORT).show()
71+
openPartyList()
72+
}
73+
}
74+
}
75+
76+
private fun openPartyList() {
77+
startActivity(Intent(this, MainActivity::class.java))
78+
finish()
79+
}
80+
}

app/src/main/java/cz/muni/fi/rpg/ui/joinParty/JoinPartyDialog.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class JoinPartyDialog(
7373
.append(".")
7474

7575
val dialog = AlertDialog.Builder(activity)
76-
.setTitle(R.string.join_party_dialog_title)
76+
.setTitle(R.string.title_joinParty)
7777
.setView(view)
7878
.setPositiveButton(R.string.button_continue, null)
7979
.setNegativeButton(R.string.button_cancel) { _, _ -> dismissAndNotify() }

0 commit comments

Comments
 (0)