Skip to content

Commit

Permalink
Merge pull request #543 from Automattic/try/stories-block-base
Browse files Browse the repository at this point in the history
Stories block
  • Loading branch information
mzorz authored Nov 4, 2020
2 parents 63ea7d2 + c343c6b commit 179b016
Show file tree
Hide file tree
Showing 18 changed files with 261 additions and 71 deletions.
11 changes: 1 addition & 10 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions app/src/main/java/com/automattic/loop/StoryComposerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import com.automattic.loop.util.ANALYTICS_TAG
import com.automattic.loop.util.CopyExternalUrisLocallyUseCase
import com.google.android.material.snackbar.Snackbar
import com.wordpress.stories.compose.ComposeLoopFrameActivity
import com.wordpress.stories.compose.FrameSaveErrorDialog
import com.wordpress.stories.compose.GenericAnnouncementDialogProvider
import com.wordpress.stories.compose.MediaPickerProvider
import com.wordpress.stories.compose.MetadataProvider
import com.wordpress.stories.compose.NotificationIntentLoader
Expand Down Expand Up @@ -50,6 +52,7 @@ class StoryComposerActivity : ComposeLoopFrameActivity(),
StoryDiscardListener,
StoriesAnalyticsListener,
PrepublishingEventProvider,
GenericAnnouncementDialogProvider,
CoroutineScope {
private var job: Job = Job()

Expand All @@ -66,6 +69,7 @@ class StoryComposerActivity : ComposeLoopFrameActivity(),
setStoriesAnalyticsListener(this)
setPrepublishingEventProvider(this)
setNotificationTrackerProvider(application as Loop) // optionally set Notification Tracker.
setGenericAnnouncementDialogProvider(this)
// The notifiationTracker needs to be something that outlives the Activity, given the Service could be running
// after the user has exited ComposeLoopFrameActivity
}
Expand Down Expand Up @@ -162,15 +166,28 @@ class StoryComposerActivity : ComposeLoopFrameActivity(),
Toast.makeText(this, "Story has been discarded!", Toast.LENGTH_SHORT).show()
}

override fun onFrameRemove(storyIndex: StoryIndex, storyFrameIndex: Int) {
Toast.makeText(this, "Story frame has been discarded!: index: " + storyFrameIndex,
Toast.LENGTH_SHORT).show()
}

override fun onStorySaveButtonPressed() {
processStorySaving()
}

override fun showGenericAnnouncementDialog() {
FrameSaveErrorDialog.newInstance(
title = getString(R.string.dialog_general_announcement_title),
message = getString(R.string.dialog_general_announcement_title)
).show(supportFragmentManager, FRAGMENT_DIALOG)
}

override fun trackStoryTextChanged(properties: Map<String, *>) {
Log.i(ANALYTICS_TAG, "story_text_changed: $properties")
}

companion object {
protected const val FRAGMENT_DIALOG = "dialog"
const val KEY_EXAMPLE_METADATA = "key_example_metadata"
const val KEY_STORY_INDEX = "key_story_index"
const val BASE_FRAME_MEDIA_ERROR_NOTIFICATION_ID: Int = 72300
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
<string name="photo_picker_wpmedia_desc">pick from WordPress media</string>
<string name="content_description_person_reading_device_notification">Person reading device with notifications</string>

<string name="dialog_general_announcement_title">General announcement</string>
<string name="dialog_general_announcement_message">This is an announcement you can make from the host app</string>

<!-- Photo picker - Loop -->
<string name="photo_picker_add_photos_to_story">Choose the photos and videos you\'d like to add to your story</string>
<!-- SD Card errors -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,11 @@ class Camera2BasicHandling : VideoRecorderFragment(), View.OnClickListener {
/**
* create video output file
*/
currentFile = FileUtils.getTempCaptureFile(activity, true)
if (useTempCaptureFile) {
currentFile = FileUtils.getTempCaptureFile(activity, true)
} else {
currentFile = FileUtils.getLoopFrameFile(activity, true)
}
currentFile?.createNewFile()

/**
Expand Down Expand Up @@ -840,7 +844,11 @@ class Camera2BasicHandling : VideoRecorderFragment(), View.OnClickListener {
override fun takePicture(onImageCapturedListener: ImageCaptureListener) {
// Create output file to hold the image
activity?.let {
currentFile = FileUtils.getTempCaptureFile(it, false)
if (useTempCaptureFile) {
currentFile = FileUtils.getTempCaptureFile(it, false)
} else {
currentFile = FileUtils.getLoopFrameFile(it, false)
}
}
currentFile?.createNewFile()

Expand Down Expand Up @@ -954,10 +962,12 @@ class Camera2BasicHandling : VideoRecorderFragment(), View.OnClickListener {

@JvmStatic fun getInstance(
textureView: AutoFitTextureView,
flashSupportChangeListener: FlashSupportChangeListener
flashSupportChangeListener: FlashSupportChangeListener,
useTempCaptureFile: Boolean
): Camera2BasicHandling {
instance.textureView = textureView
instance.flashSupportChangeListener = flashSupportChangeListener
instance.useTempCaptureFile = useTempCaptureFile
return instance
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ class CameraXBasicHandling : VideoRecorderFragment() {
@SuppressLint("RestrictedApi")
override fun startRecordingVideo(finishedListener: VideoRecorderFinished?) {
activity?.let {
currentFile = FileUtils.getTempCaptureFile(it, true)
if (useTempCaptureFile) {
currentFile = FileUtils.getTempCaptureFile(it, true)
} else {
currentFile = FileUtils.getLoopFrameFile(it, true)
}
}

currentFile?.let {
Expand Down Expand Up @@ -226,7 +230,11 @@ class CameraXBasicHandling : VideoRecorderFragment() {
override fun takePicture(onImageCapturedListener: ImageCaptureListener) {
// Create output file to hold the image
context?.let { context ->
currentFile = FileUtils.getTempCaptureFile(context, false).apply { createNewFile() }
if (useTempCaptureFile) {
currentFile = FileUtils.getTempCaptureFile(context, false).apply { createNewFile() }
} else {
currentFile = FileUtils.getLoopFrameFile(context, false).apply { createNewFile() }
}

currentFile?.let {
// Setup image capture metadata
Expand Down Expand Up @@ -326,10 +334,12 @@ class CameraXBasicHandling : VideoRecorderFragment() {

@JvmStatic fun getInstance(
textureView: AutoFitTextureView,
flashSupportChangeListener: FlashSupportChangeListener
flashSupportChangeListener: FlashSupportChangeListener,
useTempCaptureFile: Boolean
): CameraXBasicHandling {
instance.textureView = textureView
instance.flashSupportChangeListener = flashSupportChangeListener
instance.useTempCaptureFile = useTempCaptureFile
return instance
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ abstract class VideoRecorderFragment : Fragment(),
prop, old, new -> flashSupportChangeListener.onFlashSupportChanged(new)
}
)
var useTempCaptureFile = true

interface FlashSupportChangeListener {
fun onFlashSupportChanged(isSupported: Boolean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class BackgroundSurfaceManager(
private val flashSupportChangeListener: FlashSupportChangeListener,
private val useCameraX: Boolean,
private val managerReadyListener: BackgroundSurfaceManagerReadyListener? = null,
private val authenticationHeadersInterface: AuthenticationHeadersInterface? = null
private val authenticationHeadersInterface: AuthenticationHeadersInterface? = null,
var useTempCaptureFile: Boolean = true
) : LifecycleObserver {
private lateinit var cameraBasicHandler: VideoRecorderFragment
private lateinit var videoPlayerHandling: VideoPlayingBasicHandling
Expand Down Expand Up @@ -360,7 +361,7 @@ class BackgroundSurfaceManager(
val cameraFragment = supportFragmentManager.findFragmentByTag(KEY_CAMERA_HANDLING_FRAGMENT_TAG)
if (cameraFragment == null) {
cameraBasicHandler = CameraXBasicHandling.getInstance(photoEditorView.textureView,
flashSupportChangeListener)
flashSupportChangeListener, useTempCaptureFile)
supportFragmentManager
.beginTransaction().add(cameraBasicHandler, KEY_CAMERA_HANDLING_FRAGMENT_TAG).commit()
} else {
Expand All @@ -369,14 +370,15 @@ class BackgroundSurfaceManager(
// the photoEditorView layout has been recreated so, re-assign its TextureView
cameraBasicHandler.textureView = photoEditorView.textureView
cameraBasicHandler.flashSupportChangeListener = flashSupportChangeListener
cameraBasicHandler.useTempCaptureFile = useTempCaptureFile
}
}
CAMERA2 -> {
// ask FragmentManager to add the headless fragment so it receives the Activity's lifecycle callback calls
val cameraFragment = supportFragmentManager.findFragmentByTag(KEY_CAMERA_HANDLING_FRAGMENT_TAG)
if (cameraFragment == null) {
cameraBasicHandler = Camera2BasicHandling.getInstance(photoEditorView.textureView,
flashSupportChangeListener)
flashSupportChangeListener, useTempCaptureFile)
supportFragmentManager
.beginTransaction().add(cameraBasicHandler, KEY_CAMERA_HANDLING_FRAGMENT_TAG).commit()
} else {
Expand All @@ -385,6 +387,7 @@ class BackgroundSurfaceManager(
// the photoEditorView layout has been recreated so, re-assign its TextureView
cameraBasicHandler.textureView = photoEditorView.textureView
cameraBasicHandler.flashSupportChangeListener = flashSupportChangeListener
cameraBasicHandler.useTempCaptureFile = useTempCaptureFile
}
// add camera handling texture listener
photoEditorView.listeners.add((cameraBasicHandler as Camera2BasicHandling).surfaceTextureListener)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import com.wordpress.stories.compose.story.StoryViewModel.StoryFrameListItemUiSt
import com.wordpress.stories.compose.story.StoryViewModelFactory
import com.wordpress.stories.compose.text.TextEditorDialogFragment
import com.wordpress.stories.compose.text.TextStyleGroupManager
import com.wordpress.stories.util.KEY_STORY_EDIT_MODE
import com.wordpress.stories.util.KEY_STORY_SAVE_RESULT
import com.wordpress.stories.util.STATE_KEY_CURRENT_STORY_INDEX
import com.wordpress.stories.util.getDisplayPixelSize
Expand Down Expand Up @@ -173,8 +174,13 @@ interface PermanentPermissionDenialDialogProvider {
fun showPermissionPermanentlyDeniedDialog(permission: String)
}

interface GenericAnnouncementDialogProvider {
fun showGenericAnnouncementDialog()
}

interface StoryDiscardListener {
fun onStoryDiscarded()
fun onFrameRemove(storyIndex: StoryIndex, storyFrameIndex: Int) // called right before actual removal
}

abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelectorTappedListener {
Expand Down Expand Up @@ -211,7 +217,7 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
private var saveServiceBound: Boolean = false
private var preHookRun: Boolean = false
private var storyIndexToSelect = -1
private var storyFrameIndexToRetry: FrameIndex = StoryRepository.DEFAULT_NONE_SELECTED
private var storyFrameIndexToRetry: FrameIndex = StoryRepository.DEFAULT_FRAME_NONE_SELECTED
private var snackbarProvider: SnackbarProvider? = null
private var mediaPickerProvider: MediaPickerProvider? = null
private var notificationIntentLoader: NotificationIntentLoader? = null
Expand All @@ -224,12 +230,17 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
private var firstIntentLoaded: Boolean = false
protected var permissionsRequestForCameraInProgress: Boolean = false
private var permissionDenialDialogProvider: PermanentPermissionDenialDialogProvider? = null
private var genericAnnouncementDialogProvider: GenericAnnouncementDialogProvider? = null
private var showGenericAnnouncementDialogWhenReady = false
private var useTempCaptureFile = true

private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
Log.d("ComposeLoopFrame", "onServiceConnected()")
val binder = service as FrameSaveService.FrameSaveServiceBinder
frameSaveService = binder.getService()
frameSaveService.useTempCaptureFile = useTempCaptureFile
frameSaveService.isEditMode = intent.getBooleanExtra(KEY_STORY_EDIT_MODE, false)

// keep these as they're changing when we call `storyViewModel.finishCurrentStory()`
val storyIndex = storyViewModel.getCurrentStoryIndex()
Expand Down Expand Up @@ -451,7 +462,8 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
}
}
},
authHeaderInterfaceBridge
authHeaderInterfaceBridge,
useTempCaptureFile
)

lifecycle.addObserver(backgroundSurfaceManager)
Expand Down Expand Up @@ -514,15 +526,23 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
if (selectedFrameIndex < storyViewModel.getCurrentStorySize()) {
storyViewModel.setSelectedFrame(selectedFrameIndex)
}
} else if (storyIndexToSelect != StoryRepository.DEFAULT_NONE_SELECTED) {
onLoadFromIntent(intent)
}
}

override fun onStart() {
super.onStart()
val selectedFrameIndex = storyViewModel.getSelectedFrameIndex()
if (selectedFrameIndex < storyViewModel.getCurrentStorySize()) {
if (!launchCameraRequestPending && !launchVideoPlayerRequestPending &&
selectedFrameIndex < storyViewModel.getCurrentStorySize()) {
updateBackgroundSurfaceUIWithStoryFrame(selectedFrameIndex)
}
// upon loading an existing Story, show the generic announcement dialog if present
if (showGenericAnnouncementDialogWhenReady) {
showGenericAnnouncementDialogWhenReady = false
genericAnnouncementDialogProvider?.showGenericAnnouncementDialog()
}
}

private fun setupStoryViewModelObservers() {
Expand Down Expand Up @@ -646,6 +666,11 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
if (storyViewModel.getCurrentStoryIndex() == StoryRepository.DEFAULT_NONE_SELECTED) {
storyViewModel.loadStory(storyIndexToSelect)
storyIndexToSelect = storyViewModel.getCurrentStoryIndex()
} else if (storyIndexToSelect != StoryRepository.DEFAULT_NONE_SELECTED &&
StoryRepository.getStoryAtIndex(storyIndexToSelect).frames.isNotEmpty()) {
storyViewModel.loadStory(storyIndexToSelect)
showGenericAnnouncementDialogWhenReady = true
return
}

if (intent.hasExtra(requestCodes.EXTRA_LAUNCH_WPSTORIES_CAMERA_REQUESTED) ||
Expand Down Expand Up @@ -677,11 +702,6 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
)
addFramesToStoryFromMediaUriList(uriList)
setDefaultSelectionAndUpdateBackgroundSurfaceUI(uriList)
} else if (storyIndexToSelect != StoryRepository.DEFAULT_NONE_SELECTED) {
if (StoryRepository.getStoryAtIndex(storyIndexToSelect).frames.isNotEmpty()) {
storyViewModel.loadStory(storyIndexToSelect)
refreshStoryFrameSelection()
}
}
}

Expand Down Expand Up @@ -920,10 +940,18 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
}
!backgroundSurfaceManager.cameraVisible() -> {
// Show discard dialog
var discardTitle = getString(R.string.dialog_discard_story_title)
var discardMessage = getString(R.string.dialog_discard_story_message)
var discardOkButton = getString(R.string.dialog_discard_story_ok_button)
if (intent.getBooleanExtra(KEY_STORY_EDIT_MODE, false)) {
discardTitle = getString(R.string.dialog_discard_story_title_edit)
discardMessage = getString(R.string.dialog_discard_story_message_edit)
discardOkButton = getString(R.string.dialog_discard_story_ok_button_edit)
}
FrameSaveErrorDialog.newInstance(
title = getString(R.string.dialog_discard_story_title),
message = getString(R.string.dialog_discard_story_message),
okButtonLabel = getString(R.string.dialog_discard_story_ok_button),
title = discardTitle,
message = discardMessage,
okButtonLabel = discardOkButton,
listener = object : FrameSaveErrorDialogOk {
override fun OnOkClicked(dialog: DialogFragment) {
addCurrentViewsToFrameAtIndex(storyViewModel.getSelectedFrameIndex())
Expand Down Expand Up @@ -981,10 +1009,13 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
if (storyViewModel.getCurrentStorySize() == 1) {
// discard the whole story
safelyDiscardCurrentStoryAndCleanUpIntent()
storyDiscardListener?.onStoryDiscarded()
} else {
// get currentFrame value as it will change after calling onAboutToDeleteStoryFrame
val currentFrameToDeleteIndex = storyViewModel.getSelectedFrameIndex()
onAboutToDeleteStoryFrame(currentFrameToDeleteIndex)
storyDiscardListener?.onFrameRemove(storyViewModel.getCurrentStoryIndex(),
currentFrameToDeleteIndex)
// now discard it from the viewModel
storyViewModel.removeFrameAt(currentFrameToDeleteIndex)
}
Expand Down Expand Up @@ -1996,6 +2027,18 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec
permissionDenialDialogProvider = provider
}

// true: default, files are created in the internal app directory and these will be cleaned on exit
// false: we won't do cleanup and the files will be saved on the app's output directory
fun setUseTempCaptureFile(useTempFiles: Boolean) {
this.useTempCaptureFile = useTempFiles
this.storyViewModel.useTempCaptureFile = useTempFiles
this.backgroundSurfaceManager.useTempCaptureFile = useTempFiles
}

fun setGenericAnnouncementDialogProvider(provider: GenericAnnouncementDialogProvider) {
genericAnnouncementDialogProvider = provider
}

class ExternalMediaPickerRequestCodesAndExtraKeys {
var PHOTO_PICKER: Int = 0 // default code, can be overriden.
// Leave this value in zero so it's evident if something is not working (will break
Expand Down
Loading

0 comments on commit 179b016

Please sign in to comment.