Skip to content

Commit

Permalink
Add platform specific share handler
Browse files Browse the repository at this point in the history
Instead of duplicating the component and accessing the context and view controller via compositions locals, we created a share handler to do that in the common module.
  • Loading branch information
msasikanth committed Oct 16, 2023
1 parent 5c3ec45 commit 0f77eef
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 127 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.sasikanth.rss.reader.feeds.ui

package dev.sasikanth.rss.reader.share

import android.content.Context
import android.content.Intent
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import dev.sasikanth.rss.reader.di.scopes.AppScope
import me.tatarka.inject.annotations.Inject

@Composable
internal actual fun ShareIconButton(content: () -> String) {
val context = LocalContext.current
@Inject
@AppScope
class AndroidShareHandler(private val context: Context) : ShareHandler {

ShareIconButtonInternal {
override fun share(content: String) {
val sendIntent =
Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, content())
putExtra(Intent.EXTRA_TEXT, content)
type = "text/plain"
}
val shareIntent = Intent.createChooser(sendIntent, null)
val shareIntent =
Intent.createChooser(sendIntent, null).apply { addFlags(FLAG_ACTIVITY_NEW_TASK) }
context.startActivity(shareIntent)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2023 Sasikanth Miriyampalli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.sasikanth.rss.reader.share

import me.tatarka.inject.annotations.Provides

actual interface ShareComponent {

@Provides fun AndroidShareHandler.bind(): ShareHandler = this
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import dev.sasikanth.rss.reader.repository.BrowserType
import dev.sasikanth.rss.reader.resources.strings.ProvideStrings
import dev.sasikanth.rss.reader.search.ui.SearchScreen
import dev.sasikanth.rss.reader.settings.ui.SettingsScreen
import dev.sasikanth.rss.reader.share.LocalShareHandler
import dev.sasikanth.rss.reader.share.ShareHandler
import dev.sasikanth.rss.reader.utils.LocalWindowSizeClass
import me.tatarka.inject.annotations.Assisted
import me.tatarka.inject.annotations.Inject
Expand All @@ -49,14 +51,16 @@ typealias App = @Composable (openLink: (String, BrowserType) -> Unit) -> Unit
fun App(
appPresenter: AppPresenter,
imageLoader: ImageLoader,
shareHandler: ShareHandler,
@Assisted openLink: (String, BrowserType) -> Unit
) {
val dynamicColorState = rememberDynamicColorState(imageLoader = imageLoader)

CompositionLocalProvider(
LocalImageLoader provides imageLoader,
LocalWindowSizeClass provides calculateWindowSizeClass(),
LocalDynamicColorState provides dynamicColorState
LocalDynamicColorState provides dynamicColorState,
LocalShareHandler provides shareHandler
) {
DynamicContentTheme(dynamicColorState) {
ProvideStrings {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ import dev.sasikanth.rss.reader.logging.LoggingComponent
import dev.sasikanth.rss.reader.network.NetworkComponent
import dev.sasikanth.rss.reader.refresh.LastUpdatedAt
import dev.sasikanth.rss.reader.sentry.SentryComponent
import dev.sasikanth.rss.reader.share.ShareComponent
import dev.sasikanth.rss.reader.utils.DefaultDispatchersProvider
import dev.sasikanth.rss.reader.utils.DispatchersProvider
import me.tatarka.inject.annotations.Provides

abstract class SharedApplicationComponent :
DataComponent, ImageLoaderComponent, SentryComponent, NetworkComponent, LoggingComponent {
DataComponent,
ImageLoaderComponent,
SentryComponent,
NetworkComponent,
LoggingComponent,
ShareComponent {

abstract val imageLoader: ImageLoader

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import dev.sasikanth.rss.reader.resources.icons.PinFilled
import dev.sasikanth.rss.reader.resources.icons.Share
import dev.sasikanth.rss.reader.resources.icons.TwineIcons
import dev.sasikanth.rss.reader.resources.strings.LocalStrings
import dev.sasikanth.rss.reader.share.LocalShareHandler
import dev.sasikanth.rss.reader.ui.AppTheme
import kotlinx.coroutines.delay

Expand Down Expand Up @@ -159,7 +160,8 @@ private fun ActionButtons(
)
}
} else {
ShareIconButton(content = { feed.link })
val shareHandler = LocalShareHandler.current
ShareIconButton(onClick = { shareHandler.share(feed.link) })
}
}
}
Expand Down Expand Up @@ -271,10 +273,8 @@ private fun FeedLabelInput(
)
}

@Composable internal expect fun ShareIconButton(content: () -> String)

@Composable
internal fun ShareIconButtonInternal(modifier: Modifier = Modifier, onClick: () -> Unit) {
internal fun ShareIconButton(modifier: Modifier = Modifier, onClick: () -> Unit) {
IconButton(modifier = modifier, onClick = onClick) {
Icon(
imageVector = TwineIcons.Share,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ import androidx.compose.ui.unit.dp
import dev.sasikanth.rss.reader.resources.icons.Bookmark
import dev.sasikanth.rss.reader.resources.icons.Bookmarked
import dev.sasikanth.rss.reader.resources.icons.Comments
import dev.sasikanth.rss.reader.resources.icons.Share
import dev.sasikanth.rss.reader.resources.icons.TwineIcons
import dev.sasikanth.rss.reader.resources.strings.LocalStrings
import dev.sasikanth.rss.reader.share.LocalShareHandler
import dev.sasikanth.rss.reader.ui.AppTheme

@Composable
Expand Down Expand Up @@ -148,12 +150,17 @@ private fun PostOptionsButtonRow(
onClick = onBookmarkClick
)

PostOptionShareIconButton(postLink)
val shareHandler = LocalShareHandler.current
PostOptionIconButton(
icon = TwineIcons.Share,
contentDescription = LocalStrings.current.share,
onClick = { shareHandler.share(postLink) }
)
}
}

@Composable
internal fun PostOptionIconButton(
private fun PostOptionIconButton(
icon: ImageVector,
contentDescription: String,
modifier: Modifier = Modifier,
Expand All @@ -176,5 +183,3 @@ internal fun PostOptionIconButton(
)
}
}

@Composable internal expect fun PostOptionShareIconButton(postLink: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2023 Sasikanth Miriyampalli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.sasikanth.rss.reader.share

expect interface ShareComponent
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2023 Sasikanth Miriyampalli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.sasikanth.rss.reader.share

import androidx.compose.runtime.staticCompositionLocalOf

interface ShareHandler {
fun share(content: String)
}

val LocalShareHandler =
staticCompositionLocalOf<ShareHandler> {
throw NullPointerException("Please provide a share handler")
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.sasikanth.rss.reader.feeds.ui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.interop.LocalUIViewController
package dev.sasikanth.rss.reader.share

import dev.sasikanth.rss.reader.di.scopes.AppScope
import kotlinx.cinterop.ExperimentalForeignApi
import me.tatarka.inject.annotations.Inject
import platform.CoreGraphics.CGRectGetMaxY
import platform.CoreGraphics.CGRectGetMidX
import platform.CoreGraphics.CGRectMake
import platform.UIKit.UIActivityViewController
import platform.UIKit.UIViewController
import platform.UIKit.popoverPresentationController

@OptIn(ExperimentalForeignApi::class)
@Composable
internal actual fun ShareIconButton(content: () -> String) {
val viewController = LocalUIViewController.current
@Inject
@AppScope
class IOSShareHandler(private val viewControllerProvider: () -> UIViewController) : ShareHandler {

ShareIconButtonInternal {
val items = listOf(content())
@OptIn(ExperimentalForeignApi::class)
override fun share(content: String) {
val viewController = viewControllerProvider()
val items = listOf(content)
val activityController = UIActivityViewController(items, null)
activityController.popoverPresentationController?.setSourceView(viewController.view)
activityController.popoverPresentationController?.setSourceRect(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2023 Sasikanth Miriyampalli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.sasikanth.rss.reader.share

import me.tatarka.inject.annotations.Provides

actual interface ShareComponent {

@Provides fun IOSShareHandler.bind(): ShareHandler = this
}

0 comments on commit 0f77eef

Please sign in to comment.