diff --git a/.github/workflows/develop_PR_builder.yml b/.github/workflows/develop_PR_builder.yml
index 0114fdef..c3a7fe5c 100644
--- a/.github/workflows/develop_PR_builder.yml
+++ b/.github/workflows/develop_PR_builder.yml
@@ -45,6 +45,7 @@ jobs:
KEY_ALIAS: ${{ secrets.SENTRY_DSN }}
KEY_PASSWORD: ${{ secrets.SENTRY_DSN }}
STORE_PASSWORD: ${{ secrets.SENTRY_DSN }}
+ FACEBOOK_APP_ID: ${{ secrets.SENTRY_DSN }}
run: |
echo sentryDsn=\"$SENTRY_DSN\" >> ./local.properties
echo kakaoApiKey=$KAKAO_API_KEY >> ./local.properties
@@ -53,6 +54,7 @@ jobs:
echo keyAlias=$KEY_ALIAS >> ./local.properties
echo keyPassword=KEY_PASSWORD >> ./local.properties
echo storePassword=$STORE_PASSWORD >> ./local.properties
+ echo facebookAppId=$FACEBOOK_APP_ID >> ./local.properties
- name: Access Firebase Service
run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > ./app/google-services.json
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e714103c..cc88876e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,7 +4,9 @@
-
+
+
if (uri != null) {
- val intent = albumItem?.let { AddPhotoActivity.getIntent(this, uri.toString(), it) }
+ val intent = albumItem?.let { AddPhotoActivity.getIntent(this, uri.toString(), it, "PICKER") }
photoCountRefreshLauncher.launch(intent)
}
}
diff --git a/app/src/main/java/com/teampophory/pophory/feature/home/add/AddPhotoBottomSheet.kt b/app/src/main/java/com/teampophory/pophory/feature/home/add/AddPhotoBottomSheet.kt
index d19033d4..7edc0ad0 100644
--- a/app/src/main/java/com/teampophory/pophory/feature/home/add/AddPhotoBottomSheet.kt
+++ b/app/src/main/java/com/teampophory/pophory/feature/home/add/AddPhotoBottomSheet.kt
@@ -22,7 +22,6 @@ import com.teampophory.pophory.feature.home.photo.AddPhotoActivity
import com.teampophory.pophory.feature.qr.QRActivity
class AddPhotoBottomSheet : BottomSheetDialogFragment() {
-
private val binding by viewBinding(BottomSheetHomeAddPhotoBinding::bind)
private val viewModel by activityViewModels()
private lateinit var imagePicker: ActivityResultLauncher
@@ -44,7 +43,7 @@ class AddPhotoBottomSheet : BottomSheetDialogFragment() {
val currentAlbumPosition = viewModel.homeState.value.currentAlbumPosition
val albumItem = viewModel.homeState.value.currentAlbums?.getOrNull(currentAlbumPosition)
if (uri != null && albumItem != null) {
- val intent = AddPhotoActivity.getIntent(context, uri.toString(), albumItem)
+ val intent = AddPhotoActivity.getIntent(context, uri.toString(), albumItem, "PICKER")
addPhotoResultLauncher.launch(intent)
}
}
@@ -57,7 +56,7 @@ class AddPhotoBottomSheet : BottomSheetDialogFragment() {
val albumItem =
viewModel.homeState.value.currentAlbums?.getOrNull(currentAlbumPosition)
if (uriString != null && albumItem != null) {
- val intent = AddPhotoActivity.getIntent(context, uriString, albumItem)
+ val intent = AddPhotoActivity.getIntent(context, uriString, albumItem, "QR")
addPhotoResultLauncher.launch(intent)
}
}
diff --git a/app/src/main/java/com/teampophory/pophory/feature/home/model/RegisterNavigationType.kt b/app/src/main/java/com/teampophory/pophory/feature/home/model/RegisterNavigationType.kt
new file mode 100644
index 00000000..f2c699f9
--- /dev/null
+++ b/app/src/main/java/com/teampophory/pophory/feature/home/model/RegisterNavigationType.kt
@@ -0,0 +1,5 @@
+package com.teampophory.pophory.feature.home.model
+
+enum class RegisterNavigationType {
+ PICKER, QR, GALLERY
+}
diff --git a/app/src/main/java/com/teampophory/pophory/feature/home/photo/AddPhotoActivity.kt b/app/src/main/java/com/teampophory/pophory/feature/home/photo/AddPhotoActivity.kt
index 539f5b94..8484bb2e 100644
--- a/app/src/main/java/com/teampophory/pophory/feature/home/photo/AddPhotoActivity.kt
+++ b/app/src/main/java/com/teampophory/pophory/feature/home/photo/AddPhotoActivity.kt
@@ -1,21 +1,27 @@
package com.teampophory.pophory.feature.home.photo
import android.app.Activity
+import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Size
+import android.widget.Toast
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isVisible
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import coil.load
import com.google.android.material.datepicker.CalendarConstraints
import com.google.android.material.datepicker.DateValidatorPointBackward
import com.google.android.material.datepicker.MaterialDatePicker
+import com.teampophory.pophory.BuildConfig
import com.teampophory.pophory.R
+import com.teampophory.pophory.common.bitmap.capture
+import com.teampophory.pophory.common.bitmap.saveToDisk
import com.teampophory.pophory.common.context.colorOf
import com.teampophory.pophory.common.context.snackBar
import com.teampophory.pophory.common.context.toast
@@ -26,10 +32,12 @@ import com.teampophory.pophory.common.time.systemNow
import com.teampophory.pophory.common.view.setOnSingleClickListener
import com.teampophory.pophory.common.view.viewBinding
import com.teampophory.pophory.databinding.ActivityAddPhotoBinding
+import com.teampophory.pophory.feature.home.model.RegisterNavigationType
import com.teampophory.pophory.feature.home.store.model.AlbumItem
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
import kotlinx.datetime.Instant
import java.text.SimpleDateFormat
import java.util.Date
@@ -63,9 +71,9 @@ class AddPhotoActivity : AppCompatActivity() {
private fun loadImageWithAdjustedSize(realImageUri: Uri, adjustedSize: Size) {
val (backgroundResource, imageView) = if (adjustedSize.width >= adjustedSize.height) {
- Pair(R.drawable.img_background_width, binding.imgHorizontal)
+ R.drawable.img_background_width to binding.imgHorizontal
} else {
- Pair(R.drawable.img_background_height, binding.imgVertical)
+ R.drawable.img_background_height to binding.imgVertical
}
binding.imgBackground.setImageResource(backgroundResource)
imageView.load(realImageUri) {
@@ -74,10 +82,10 @@ class AddPhotoActivity : AppCompatActivity() {
}
private fun initView() {
- binding.toolbarAddPhoto.btnBack.setOnClickListener {
+ binding.btnBack.setOnClickListener {
finish()
}
- binding.toolbarAddPhoto.txtToolbarTitle.text = "사진 추가"
+ binding.txtToolbarTitle.text = "사진 추가"
binding.layoutDate.setOnClickListener {
viewModel.onCreatedAtPressed()
}
@@ -91,6 +99,33 @@ class AddPhotoActivity : AppCompatActivity() {
setResult(Activity.RESULT_CANCELED)
finish()
}
+ binding.btnShare.setOnSingleClickListener {
+ lifecycleScope.launch {
+ val bitmap = binding.layoutImage.capture(this@AddPhotoActivity)
+ val shareImageUri = bitmap.saveToDisk(this@AddPhotoActivity)
+ val intent = Intent("com.instagram.share.ADD_TO_STORY").apply {
+ putExtra("source_application", BuildConfig.FACEBOOK_APP_ID)
+ type = "image/png"
+ putExtra("interactive_asset_uri", shareImageUri)
+ putExtra("top_background_color", "#000000")
+ putExtra("bottom_background_color", "#000000")
+ }
+ grantUriPermission(
+ "com.instagram.android",
+ shareImageUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ )
+ try {
+ startActivity(intent)
+ } catch (e: ActivityNotFoundException) {
+ Toast.makeText(
+ this@AddPhotoActivity,
+ "인스타그램 앱이 존재하지 않습니다.",
+ Toast.LENGTH_SHORT,
+ ).show()
+ }
+ }
+ }
}
private fun subscribeEvent() {
@@ -112,7 +147,8 @@ class AddPhotoActivity : AppCompatActivity() {
.setEnd(Instant.systemNow().toEpochMilliseconds()).build(),
)
.setSelection(
- currentCreatedAt + TimeZone.getDefault().getOffset(currentCreatedAt),
+ currentCreatedAt + TimeZone.getDefault()
+ .getOffset(currentCreatedAt),
)
.build()
picker.show(supportFragmentManager, "datePicker")
@@ -157,18 +193,30 @@ class AddPhotoActivity : AppCompatActivity() {
binding.txtStudio.setTextColor(colorOf(com.teampophory.pophory.designsystem.R.color.gray_40))
}
}.launchIn(lifecycleScope)
+ viewModel.type
+ .flowWithLifecycle(lifecycle)
+ .onEach {
+ binding.btnShare.isVisible = it != RegisterNavigationType.PICKER
+ }.launchIn(lifecycleScope)
}
companion object {
private const val IMAGE_URL_EXTRA = "imageUri"
const val ALBUM_ITEM_EXTRA = "albumItem"
const val IMAGE_MIME_TYPE = "image/*"
+ private const val TYPE = "type"
@JvmStatic
- fun getIntent(context: Context, imageUri: String, albumItem: AlbumItem): Intent =
+ fun getIntent(
+ context: Context,
+ imageUri: String,
+ albumItem: AlbumItem,
+ type: String,
+ ): Intent =
Intent(context, AddPhotoActivity::class.java).apply {
putExtra(IMAGE_URL_EXTRA, imageUri)
putExtra(ALBUM_ITEM_EXTRA, albumItem)
+ putExtra(TYPE, type)
}
}
}
diff --git a/app/src/main/java/com/teampophory/pophory/feature/home/photo/AddPhotoViewModel.kt b/app/src/main/java/com/teampophory/pophory/feature/home/photo/AddPhotoViewModel.kt
index d760476b..9e6ff52f 100644
--- a/app/src/main/java/com/teampophory/pophory/feature/home/photo/AddPhotoViewModel.kt
+++ b/app/src/main/java/com/teampophory/pophory/feature/home/photo/AddPhotoViewModel.kt
@@ -8,6 +8,7 @@ import com.teampophory.pophory.common.time.systemNow
import com.teampophory.pophory.data.model.photo.Studio
import com.teampophory.pophory.domain.model.S3Image
import com.teampophory.pophory.domain.repository.photo.PhotoRepository
+import com.teampophory.pophory.feature.home.model.RegisterNavigationType
import com.teampophory.pophory.feature.home.photo.model.StudioUiModel
import com.teampophory.pophory.feature.home.photo.model.toUiModel
import com.teampophory.pophory.feature.home.store.model.AlbumItem
@@ -43,6 +44,12 @@ class AddPhotoViewModel @Inject constructor(
private var imageRequestBody: RequestBody? = null
private var currentImageSize: Size? = null
private var currentFileName: String? = null
+ private val _type = MutableStateFlow(
+ RegisterNavigationType.valueOf(
+ savedStateHandle.get("type").orEmpty(),
+ ),
+ )
+ val type = _type.asStateFlow()
private val _createdAt = MutableStateFlow(Instant.systemNow().toEpochMilliseconds())
val createdAt = _createdAt.asStateFlow()
private val allStudio = MutableStateFlow>(emptyList())
diff --git a/app/src/main/java/com/teampophory/pophory/feature/home/store/StoreFragment.kt b/app/src/main/java/com/teampophory/pophory/feature/home/store/StoreFragment.kt
index 8a4b101c..dc9a1304 100644
--- a/app/src/main/java/com/teampophory/pophory/feature/home/store/StoreFragment.kt
+++ b/app/src/main/java/com/teampophory/pophory/feature/home/store/StoreFragment.kt
@@ -235,6 +235,7 @@ class StoreFragment : Fragment() {
context = requireContext(),
imageUri = imageUri.toString(),
albumItem = albumItem,
+ type = "GALLERY",
).let(albumListAddPhotoLauncher::launch)
}
}
diff --git a/app/src/main/res/layout/activity_add_photo.xml b/app/src/main/res/layout/activity_add_photo.xml
index 4cd80680..8c4513b6 100644
--- a/app/src/main/res/layout/activity_add_photo.xml
+++ b/app/src/main/res/layout/activity_add_photo.xml
@@ -5,17 +5,60 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+
+
+
+
+
+
+
+
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@id/toolbar">
+ bitmap.compress(format, quality, out)
+ out.flush()
+ }
+}
+
+suspend fun scanFilePath(context: Context, filePath: String): Uri? {
+ return suspendCancellableCoroutine { continuation ->
+ MediaScannerConnection.scanFile(
+ context,
+ arrayOf(filePath),
+ arrayOf("image/png"),
+ ) { _, scannedUri ->
+ if (scannedUri == null) {
+ continuation.cancel(Exception("File $filePath could not be scanned"))
+ } else {
+ continuation.resume(scannedUri)
+ }
+ }
+ }
+}
+
+suspend fun View.capture(activity: Activity) = suspendCancellableCoroutine { continuation ->
+ val bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)
+ val location = IntArray(2)
+ getLocationInWindow(location)
+ PixelCopy.request(
+ activity.window,
+ Rect(location[0], location[1], location[0] + width, location[1] + height),
+ bitmap,
+ {
+ if (it == PixelCopy.SUCCESS) {
+ continuation.resume(bitmap)
+ } else {
+ continuation.resumeWithException(Exception("Unable to load bitmap from view"))
+ }
+ },
+ Handler(Looper.getMainLooper()),
+ )
+}