feat(common-ui): image share (#22)

This commit is contained in:
Diego Beraldin 2023-09-17 13:13:25 +02:00 committed by GitHub
parent 0f36883dc7
commit 63d492c388
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 141 additions and 5 deletions

View File

@ -4,6 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.Comm
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel
@ -97,4 +98,9 @@ actual fun getCreatePostViewModel(communityId: Int): CreatePostViewModel {
parameters = { parametersOf(communityId) } parameters = { parametersOf(communityId) }
) )
return res return res
}
actual fun getZoomableImageViewModel(): ZoomableImageViewModel {
val res: ZoomableImageViewModel by inject(ZoomableImageViewModel::class.java)
return res
} }

View File

@ -9,6 +9,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.Crea
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.DefaultNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.DefaultNavigationCoordinator
@ -114,4 +116,10 @@ val commonUiModule = module {
postsRepository = get(), postsRepository = get(),
) )
} }
factory {
ZoomableImageViewModel(
mvi = DefaultMviModel(ZoomableImageMviModel.UiState()),
shareHelper = get(),
)
}
} }

View File

@ -4,6 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.Comm
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel
@ -52,4 +53,6 @@ expect fun getCreateCommentViewModel(
expect fun getCreatePostViewModel( expect fun getCreatePostViewModel(
communityId: Int, communityId: Int,
): CreatePostViewModel ): CreatePostViewModel
expect fun getZoomableImageViewModel(): ZoomableImageViewModel

View File

@ -0,0 +1,14 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.image
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
interface ZoomableImageMviModel :
MviModel<ZoomableImageMviModel.Intent, ZoomableImageMviModel.UiState, ZoomableImageMviModel.Effect> {
sealed interface Intent {
data class Share(val url: String) : Intent
}
data class UiState(val loading: Boolean = false)
sealed interface Effect
}

View File

@ -1,13 +1,14 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.image package com.github.diegoberaldin.raccoonforlemmy.core.commonui.image
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
@ -16,11 +17,13 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import com.github.diegoberaldin.racconforlemmy.core.utils.onClick import com.github.diegoberaldin.racconforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ZoomableImage import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ZoomableImage
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getZoomableImageViewModel
class ZoomableImageScreen( class ZoomableImageScreen(
private val url: String, private val url: String,
@ -29,19 +32,33 @@ class ZoomableImageScreen(
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
override fun Content() { override fun Content() {
val model = rememberScreenModel { getZoomableImageViewModel() }
model.bindToLifecycle(key)
val navigator = remember { getNavigationCoordinator().getRootNavigator() } val navigator = remember { getNavigationCoordinator().getRootNavigator() }
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { navigationIcon = {
Image( Icon(
modifier = Modifier.onClick { modifier = Modifier.onClick {
navigator?.pop() navigator?.pop()
}, },
imageVector = Icons.Default.ArrowBack, imageVector = Icons.Default.ArrowBack,
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface), tint = MaterialTheme.colorScheme.onSurface,
)
},
actions = {
Icon(
modifier = Modifier.onClick {
model.reduce(ZoomableImageMviModel.Intent.Share(url))
},
imageVector = Icons.Default.Share,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurface,
) )
} }
) )

View File

@ -0,0 +1,21 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.image
import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.racconforlemmy.core.utils.ShareHelper
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
class ZoomableImageViewModel(
private val mvi: DefaultMviModel<ZoomableImageMviModel.Intent, ZoomableImageMviModel.UiState, ZoomableImageMviModel.Effect>,
private val shareHelper: ShareHelper,
) : ScreenModel,
MviModel<ZoomableImageMviModel.Intent, ZoomableImageMviModel.UiState, ZoomableImageMviModel.Effect> by mvi {
override fun reduce(intent: ZoomableImageMviModel.Intent) {
when (intent) {
is ZoomableImageMviModel.Intent.Share -> {
shareHelper.shareImage(intent.url, "image/*")
}
}
}
}

View File

@ -4,6 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communityInfo.Comm
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createcomment.CreateCommentViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.createpost.CreatePostViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.image.ZoomableImageViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.instanceinfo.InstanceInfoViewModel
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation.NavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel import com.github.diegoberaldin.raccoonforlemmy.core.commonui.postdetail.PostDetailViewModel
@ -49,9 +50,13 @@ actual fun getCreateCommentViewModel(postId: Int, parentId: Int?): CreateComment
actual fun getCreatePostViewModel(communityId: Int): CreatePostViewModel = actual fun getCreatePostViewModel(communityId: Int): CreatePostViewModel =
CommonUiViewModelHelper.getCreatePostModel(communityId) CommonUiViewModelHelper.getCreatePostModel(communityId)
actual fun getZoomableImageViewModel(): ZoomableImageViewModel =
CommonUiViewModelHelper.zoomableImageModel
object CommonUiViewModelHelper : KoinComponent { object CommonUiViewModelHelper : KoinComponent {
val navigationCoordinator: NavigationCoordinator by inject() val navigationCoordinator: NavigationCoordinator by inject()
val zoomableImageModel: ZoomableImageViewModel by inject()
fun getPostDetailModel(post: PostModel): PostDetailViewModel { fun getPostDetailModel(post: PostModel): PostDetailViewModel {
val model: PostDetailViewModel by inject( val model: PostDetailViewModel by inject(

View File

@ -0,0 +1,30 @@
package com.github.diegoberaldin.racconforlemmy.core.utils
import android.content.Context
import android.content.Intent
import org.koin.dsl.module
class DefaultShareHelper(
private val context: Context,
) : ShareHelper {
override fun shareImage(url: String, mimeType: String) {
val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, url)
type = mimeType
}
val shareIntent = Intent.createChooser(sendIntent, null).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
context.startActivity(shareIntent)
}
}
actual val shareHelperModule = module {
single<ShareHelper> {
DefaultShareHelper(
context = get(),
)
}
}

View File

@ -0,0 +1,9 @@
package com.github.diegoberaldin.racconforlemmy.core.utils
import org.koin.core.module.Module
interface ShareHelper {
fun shareImage(url: String, mimeType: String)
}
expect val shareHelperModule: Module

View File

@ -0,0 +1,19 @@
package com.github.diegoberaldin.racconforlemmy.core.utils
import org.koin.dsl.module
import platform.UIKit.UIActivityViewController
import platform.UIKit.UIApplication
class DefaultShareHelper() : ShareHelper {
override fun shareImage(url: String, mimeType: String) {
val shareActivity = UIActivityViewController(listOf(url), null)
val rvc = UIApplication.sharedApplication().keyWindow?.rootViewController
rvc?.presentViewController(shareActivity, true, null)
}
}
actual val shareHelperModule = module {
single<ShareHelper> {
DefaultShareHelper()
}
}

View File

@ -1,6 +1,7 @@
package com.github.diegoberaldin.raccoonforlemmy.di package com.github.diegoberaldin.raccoonforlemmy.di
import com.github.diegoberaldin.racconforlemmy.core.utils.hapticFeedbackModule import com.github.diegoberaldin.racconforlemmy.core.utils.hapticFeedbackModule
import com.github.diegoberaldin.racconforlemmy.core.utils.shareHelperModule
import com.github.diegoberaldin.raccoonforlemmy.core.api.di.coreApiModule import com.github.diegoberaldin.raccoonforlemmy.core.api.di.coreApiModule
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.coreAppearanceModule import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.coreAppearanceModule
import com.github.diegoberaldin.raccoonforlemmy.core.crashreport.di.crashReportModule import com.github.diegoberaldin.raccoonforlemmy.core.crashreport.di.crashReportModule
@ -26,6 +27,7 @@ val sharedHelperModule = module {
crashReportModule, crashReportModule,
hapticFeedbackModule, hapticFeedbackModule,
localizationModule, localizationModule,
shareHelperModule,
homeTabModule, homeTabModule,
inboxTabModule, inboxTabModule,
profileTabModule, profileTabModule,

View File

@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.di
import com.github.diegoberaldin.racconforlemmy.core.utils.AppInfo import com.github.diegoberaldin.racconforlemmy.core.utils.AppInfo
import com.github.diegoberaldin.racconforlemmy.core.utils.hapticFeedbackModule import com.github.diegoberaldin.racconforlemmy.core.utils.hapticFeedbackModule
import com.github.diegoberaldin.racconforlemmy.core.utils.shareHelperModule
import com.github.diegoberaldin.raccoonforlemmy.core.api.di.coreApiModule import com.github.diegoberaldin.raccoonforlemmy.core.api.di.coreApiModule
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.coreAppearanceModule import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.coreAppearanceModule
import com.github.diegoberaldin.raccoonforlemmy.core.crashreport.di.crashReportModule import com.github.diegoberaldin.raccoonforlemmy.core.crashreport.di.crashReportModule
@ -29,6 +30,7 @@ fun initKoin() {
crashReportModule, crashReportModule,
hapticFeedbackModule, hapticFeedbackModule,
localizationModule, localizationModule,
shareHelperModule,
homeTabModule, homeTabModule,
inboxTabModule, inboxTabModule,
profileTabModule, profileTabModule,