# Player configurations (Flutter)

We have the following three entries to open the player.

1. `VideoFeed` widget
2. `CircleStory` widget
3. `StoryBlock` widget
4. `openVideoPlayer` API

When customizing the player, you need to handle the above entries if you use them.

### Configuration reference

1. [VideoPlayerConfiguration](https://eng.firework.com/fw_flutter_sdk/v2/fw_flutter_sdk/VideoPlayerConfiguration-class.html)
2. [StoryBlockConfiguration](https://eng.firework.com/fw_flutter_sdk/v2/fw_flutter_sdk/StoryBlockConfiguration-class.html)
3. [OpenVideoPlayerConfiguration](https://eng.firework.com/fw_flutter_sdk/v2/fw_flutter_sdk/OpenVideoPlayerConfiguration-class.html)

### Customize player styles

As the following code snippets, we could customize styles for video overlay CTA, action button, countdown timer, etc.

#### Customize player styles for video feed widget

```dart
// Configure player configuration for VideoFeed widget
final videoPlayerConfiguration = VideoPlayerConfiguration();

// Customize the video overlay CTA button style
videoPlayerConfiguration.ctaButtonStyle = VideoPlayerCTAStyle(
  backgroundColor: "#2089ff",
  textColor: "#ffffff",
  fontSize: 14,
  shape: ButtonShape.roundRectangle,
  iOSFontInfo: IOSFontInfo(
    fontName: "Helvetica",
    systemFontStyle: IOSSystemFontStyle.italic,
    systemFontWeight: IOSSystemFontWeight.heavy,
  ), // or ButtonShape.oval
);

// Customize the style of action button style, such as share button
videoPlayerConfiguration.actionButtonStyle = VideoPlayerActionButtonStyle(
  backgroundColor: "#2089ff",
  textColor: "#ffffff",
  dividingLineColor: "#ffffff",
  shape: ButtonShape.oval,
);

// Customize the style of cancel button style
videoPlayerConfiguration.cancelButtonStyle = VideoPlayerActionButtonStyle(
  backgroundColor: "#ffffff",
  textColor: "#000000",
  shape: ButtonShape.oval,
);

// Specifies the appearance of the countdown timer
videoPlayerConfiguration.countdownTimerConfiguration =
    CountdownTimerConfiguration(
  appearance: CountdownTimerAppearanceMode.light,
);

VideoFeed(
  source: VideoFeedSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  videoPlayerConfiguration: videoPlayerConfiguration,
);
```

#### Customize player styles for circle story widget

```dart
// Configure player configuration for VideoFeed widget
final videoPlayerConfiguration = VideoPlayerConfiguration();

// Customize the video overlay CTA button style
videoPlayerConfiguration.ctaButtonStyle = VideoPlayerCTAStyle(
  backgroundColor: "#2089ff",
  textColor: "#ffffff",
  fontSize: 14,
  shape: ButtonShape.roundRectangle,
  iOSFontInfo: IOSFontInfo(
    fontName: "Helvetica",
    systemFontStyle: IOSSystemFontStyle.italic,
    systemFontWeight: IOSSystemFontWeight.heavy,
  ), // or ButtonShape.oval
);

// Customize the style of action button style, such as share button
videoPlayerConfiguration.actionButtonStyle = VideoPlayerActionButtonStyle(
  backgroundColor: "#2089ff",
  textColor: "#ffffff",
  dividingLineColor: "#ffffff",
  shape: ButtonShape.oval,
);

// Customize the style of cancel button style
videoPlayerConfiguration.cancelButtonStyle = VideoPlayerActionButtonStyle(
  backgroundColor: "#ffffff",
  textColor: "#000000",
  shape: ButtonShape.oval,
);

// Specifies the appearance of the countdown timer
videoPlayerConfiguration.countdownTimerConfiguration =
    CountdownTimerConfiguration(
  appearance: CountdownTimerAppearanceMode.light,
);

CircleStory(
  source: VideoFeedSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  videoPlayerConfiguration: videoPlayerConfiguration,
);
```

#### Customize player styles for story block widget

```dart
// Configure player configuration for StoryBlock widget
final storyBlockConfiguration = StoryBlockConfiguration();

// Customize the video overlay CTA button style
storyBlockConfiguration.ctaButtonStyle = VideoPlayerCTAStyle(
  backgroundColor: "#2089ff",
  textColor: "#ffffff",
  fontSize: 14,
  shape: ButtonShape.roundRectangle,
  iOSFontInfo: IOSFontInfo(
    fontName: "Helvetica",
    systemFontStyle: IOSSystemFontStyle.italic,
    systemFontWeight: IOSSystemFontWeight.heavy,
  ), // or ButtonShape.oval
);

// Customize the style of Action button style, such as share button
storyBlockConfiguration.actionButtonStyle = VideoPlayerActionButtonStyle(
  backgroundColor: "#2089ff",
  textColor: "#ffffff",
  dividingLineColor: "#ffffff",
  shape: ButtonShape.oval,
);

// Customize the style of cancel button style
storyBlockConfiguration.cancelButtonStyle = VideoPlayerActionButtonStyle(
  backgroundColor: "#ffffff",
  textColor: "#000000",
  shape: ButtonShape.oval,
);

// Specifies the appearance of the countdown timer.
storyBlockConfiguration.countdownTimerConfiguration =
    CountdownTimerConfiguration(
  appearance: CountdownTimerAppearanceMode.light,
);

StoryBlock(
  source: StoryBlockSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  storyBlockConfiguration: storyBlockConfiguration,
);
```

#### Customize player styles for openVideoPlayer API

```dart
// Configure player configuration for openVideoPlayer API
OpenVideoPlayerConfiguration openVideoPlayerConfiguration =
    OpenVideoPlayerConfiguration();

// Customize the video overlay CTA button style
openVideoPlayerConfiguration.ctaButtonStyle = VideoPlayerCTAStyle(
  backgroundColor: "#2089ff",
  textColor: "#ffffff",
  fontSize: 14,
  shape: ButtonShape.roundRectangle,
  iOSFontInfo: IOSFontInfo(
    fontName: "Helvetica",
    systemFontStyle: IOSSystemFontStyle.italic,
    systemFontWeight: IOSSystemFontWeight.heavy,
  ), // or ButtonShape.oval
);

// Customize the style of Action button style, such as share button
openVideoPlayerConfiguration.actionButtonStyle =
    VideoPlayerActionButtonStyle(
  backgroundColor: "#2089ff",
  textColor: "#ffffff",
  dividingLineColor: "#ffffff",
  shape: ButtonShape.oval,
);

// Customize the style of cancel button style
openVideoPlayerConfiguration.cancelButtonStyle =
    VideoPlayerActionButtonStyle(
  backgroundColor: "#ffffff",
  textColor: "#000000",
  shape: ButtonShape.oval,
);

// Specifies the appearance of the countdown timer
openVideoPlayerConfiguration.countdownTimerConfiguration =
    CountdownTimerConfiguration(
  appearance: CountdownTimerAppearanceMode.light,
);

FireworkSDK.getInstance().openVideoPlayer(
  url: url,
  config: openVideoPlayerConfiguration,
);
```

### Enable PiP(Picture in Picture)

#### Set up the iOS project

To enable PiP outside the iOS app, you also need to add "Audio, Airplay, and Picture in Picture" background mode via Signing & Capabilities in your iOS project settings(as shown in the following screenshot). More information about this can be found here: [Apple Documentation](https://developer.apple.com/documentation/avfoundation/media_playback/configuring_the_audio_playback_of_ios_and_tvos_apps)

<figure><img src="https://688917408-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLoGG8m6bokS9YTmS7m%2Fuploads%2Fgit-blob-cb55b55235ae986bd288f78d66704f92f5e428a1%2Fimage%20(39).png?alt=media" alt=""><figcaption></figcaption></figure>

#### Set enablePictureInPicture to true on Dart side

```dart
// Enable PiP for VideoFeed widget
VideoFeed(
  height: 200,
  source: VideoFeedSource.discover,
  enablePictureInPicture: true,
);

// Enable PiP for CircleStory widget
CircleStory(
  height: 200,
  source: VideoFeedSource.discover,
  enablePictureInPicture: true,
);

// Enable PiP for StoryBlock widget
StoryBlock(
  height: 400,
  source: StoryBlockSource.discover,
  enablePictureInPicture: true,
);

// Enable PiP for openVideoPlayer API
FireworkSDK.getInstance().openVideoPlayer(
  url: url,
  config: OpenVideoPlayerConfiguration(
    enablePictureInPicture: true,
  ),
);
```

### Customize player icons

#### Set up iOS project

Add the custom icons to the asset catalogs(e.g. Images.xcassets, Assets.xcassets or other names) in your iOS project. Such as:

<figure><img src="https://688917408-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLoGG8m6bokS9YTmS7m%2Fuploads%2Fgit-blob-adb419adbe48accceacdce1282608ce82b2dd3fe%2Fimage%20(36).png?alt=media" alt="" width="375"><figcaption></figcaption></figure>

For more details, please refer to <https://developer.apple.com/documentation/xcode/adding-images-to-your-xcode-project>

#### Set up Android project

Add the custom icons to the drawable directory([App resources overview](https://developer.android.com/guide/topics/resources/providing-resources#ResourcesFromCode) and[ Support different pixel densities](https://developer.android.com/training/multiscreen/screendensities)) in your Android project. Such as:

<figure><img src="https://688917408-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MLoGG8m6bokS9YTmS7m%2Fuploads%2Fgit-blob-e5c2a14d85f8f78b984d6f8edbb3116ce5117e63%2Fimage%20(38).png?alt=media" alt="" width="375"><figcaption></figcaption></figure>

#### Configure the icon names on the Dart side

```dart
// Configure player configuration for VideoFeed widget
final videoPlayerConfiguration = VideoPlayerConfiguration();
videoPlayerConfiguration.buttonConfiguration =
    VideoPlayerButtonConfiguration(
  videoDetailButton: ButtonInfo(imageName: "custom_more"),
  closeButton: ButtonInfo(imageName: "custom_close"),
  pipButton: ButtonInfo(imageName: "custom_pip"),
  muteButton: ButtonInfo(imageName: "custom_mute"),
  unmuteButton: ButtonInfo(imageName: "custom_unmute"),
  playButton: ButtonInfo(imageName: "custom_play"),
  pauseButton: ButtonInfo(imageName: "custom_pause"),
);
VideoFeed(
  source: VideoFeedSource.discover,
  videoPlayerConfiguration: videoPlayerConfiguration,
);

// Configure player configuration for VideoFeed widget
final videoPlayerConfiguration = VideoPlayerConfiguration();
videoPlayerConfiguration.buttonConfiguration =
    VideoPlayerButtonConfiguration(
  videoDetailButton: ButtonInfo(imageName: "custom_more"),
  closeButton: ButtonInfo(imageName: "custom_close"),
  pipButton: ButtonInfo(imageName: "custom_pip"),
  muteButton: ButtonInfo(imageName: "custom_mute"),
  unmuteButton: ButtonInfo(imageName: "custom_unmute"),
  playButton: ButtonInfo(imageName: "custom_play"),
  pauseButton: ButtonInfo(imageName: "custom_pause"),
);
CircleStory(
  source: VideoFeedSource.discover,
  videoPlayerConfiguration: videoPlayerConfiguration,
);

// Configure player configuration for StoryBlock widget
final storyBlockConfiguration = StoryBlockConfiguration();
storyBlockConfiguration.buttonConfiguration =
    VideoPlayerButtonConfiguration(
  videoDetailButton: ButtonInfo(imageName: "custom_more"),
  closeButton: ButtonInfo(imageName: "custom_close"),
  pipButton: ButtonInfo(imageName: "custom_pip"),
  muteButton: ButtonInfo(imageName: "custom_mute"),
  unmuteButton: ButtonInfo(imageName: "custom_unmute"),
  playButton: ButtonInfo(imageName: "custom_play"),
  pauseButton: ButtonInfo(imageName: "custom_pause"),
);
StoryBlock(
  source: StoryBlockSource.discover,
  storyBlockConfiguration: storyBlockConfiguration,
);

// Configure player configuration for openVideoPlayer API
OpenVideoPlayerConfiguration openVideoPlayerConfiguration =
    OpenVideoPlayerConfiguration();
openVideoPlayerConfiguration.buttonConfiguration =
    VideoPlayerButtonConfiguration(
  videoDetailButton: ButtonInfo(imageName: "custom_more"),
  closeButton: ButtonInfo(imageName: "custom_close"),
  pipButton: ButtonInfo(imageName: "custom_pip"),
  muteButton: ButtonInfo(imageName: "custom_mute"),
  unmuteButton: ButtonInfo(imageName: "custom_unmute"),
  playButton: ButtonInfo(imageName: "custom_play"),
  pauseButton: ButtonInfo(imageName: "custom_pause"),
);
FireworkSDK.getInstance().openVideoPlayer(
  url: "url",
  config: openVideoPlayerConfiguration,
);
```

### Customize player logo

To display the channel logo instead of the more icon (three dots) in the player, you could refer to the following code snippets.

```dart
// Configure player configuration for VideoFeed widget
final videoPlayerConfiguration = VideoPlayerConfiguration();
videoPlayerConfiguration.videoPlayerLogoConfiguration =
    VideoPlayerLogoConfiguration(
  option: VideoPlayerLogoOption.creator,
  encodedId: "your encoded channel id",
);

VideoFeed(
  source: VideoFeedSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  videoPlayerConfiguration: videoPlayerConfiguration,
);

// Configure player configuration for CircleStory widget
final videoPlayerConfiguration = VideoPlayerConfiguration();
videoPlayerConfiguration.videoPlayerLogoConfiguration =
    VideoPlayerLogoConfiguration(
  option: VideoPlayerLogoOption.creator,
  encodedId: "your encoded channel id",
);

CircleStory(
  source: VideoFeedSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  videoPlayerConfiguration: videoPlayerConfiguration,
);

// Configure player configuration for StoryBlock widget
final storyBlockConfiguration = StoryBlockConfiguration();
storyBlockConfiguration.videoPlayerLogoConfiguration =
    VideoPlayerLogoConfiguration(
  option: VideoPlayerLogoOption.creator,
  encodedId: "your encoded channel id",
);
StoryBlock(
  source: StoryBlockSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  storyBlockConfiguration: storyBlockConfiguration,
);

// Configure player configuration for openVideoPlayer API
OpenVideoPlayerConfiguration openVideoPlayerConfiguration =
    OpenVideoPlayerConfiguration();
openVideoPlayerConfiguration.videoPlayerLogoConfiguration =
    VideoPlayerLogoConfiguration(
  option: VideoPlayerLogoOption.creator,
  encodedId: "your encoded channel id",
);
FireworkSDK.getInstance().openVideoPlayer(
  url: "url",
  config: openVideoPlayerConfiguration,
);
```

### Customize Ad badge

We offer a global API for customizing ad badges, and these configurations are applicable to both the player and the video feed. The API is `FireworkSDK.getInstance().adBadgeConfiguration`.

```dart
FireworkSDK.getInstance().adBadgeConfiguration = AdBadgeConfiguration(
  badgeTextType: AdBadgeTextType.ad, // or AdBadgeTextType.sponsored
  backgroundColor: "#ffffff",
  textColor: "#000000",
  androidFontInfo: AndroidFontInfo(
    isCustom: false,
    typefaceName: "SANS_SERIF",
  ),
);
```

### Customize video or livestream shared URL

To customize video or livestream shared URL, you could use `FireworkSDK.getInstance().onCustomShareUrl` to customize the URL. The sample codes are:

```dart
FireworkSDK.getInstance().onCustomShareUrl =
    (CustomShareUrlEvent? event) async {
  if (event != null) {
    final originalUrl = event.url;
    final video = event.video;

    // Here, you can write code to customize the shared URL based on event parameters,
    // such as the original URL and video details.
    // For example, you could use appsFlyerSdk.generateInviteLink to generate AppsFlyer OneLink.
    // The doc is https://github.com/AppsFlyerSDK/appsflyer-flutter-plugin/blob/master/doc/AdvancedAPI.md#-user-invite
    
    // Return the customized shared URL.
    // For example, the customized shared URL can be an AppsFlyer OneLink.
    return CustomShareUrlResult(
      url: "customized shared url",
    );
  }
  
  // If null is returned, the default shared URL will be used.
  return null;
};
```

### Customize other player configurations

```dart
// Configure player configuration for VideoFeed widget
final videoPlayerConfiguration = VideoPlayerConfiguration();
// Configure player style: full or fit
videoPlayerConfiguration.playerStyle = VideoPlayerStyle.full;
// Configure video complete action: advanceToNext or loop
// On iOS, the property only applies to full-screen mode but not to embedded mode
// On Android, the property applies to both full-screen and embedded modes
videoPlayerConfiguration.videoCompleteAction =
    VideoPlayerCompleteAction.advanceToNext;
// Indicates if the video player shows share button
videoPlayerConfiguration.showShareButton = true;
// Indicates if the video player shows playback button
videoPlayerConfiguration.showPlaybackButton = true;
// Indicates if the video player shows mute button
videoPlayerConfiguration.showMuteButton = true;
// Specifies if the video detail title should be showed
videoPlayerConfiguration.showVideoDetailTitle = true;

VideoFeed(
  source: VideoFeedSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  videoPlayerConfiguration: videoPlayerConfiguration,
);

// Configure player configuration for CircleStory widget
final videoPlayerConfiguration = VideoPlayerConfiguration();
// Configure player style: full or fit
videoPlayerConfiguration.playerStyle = VideoPlayerStyle.full;
// Configure video complete action: advanceToNext or loop
// On iOS, the property only applies to full-screen mode but not to embedded mode
// On Android, the property applies to both full-screen and embedded modes
videoPlayerConfiguration.videoCompleteAction =
    VideoPlayerCompleteAction.advanceToNext;
// Indicates if the video player shows share button
videoPlayerConfiguration.showShareButton = true;
// Indicates if the video player shows playback button
videoPlayerConfiguration.showPlaybackButton = true;
// Indicates if the video player shows mute button
videoPlayerConfiguration.showMuteButton = true;
// Specifies if the video detail title should be showed
videoPlayerConfiguration.showVideoDetailTitle = true;

CircleStory(
  source: VideoFeedSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  videoPlayerConfiguration: videoPlayerConfiguration,
);

// Configure player configuration for StoryBlock widget
final storyBlockConfiguration = StoryBlockConfiguration();
// Configure player style: full or fit
storyBlockConfiguration.playerStyle = VideoPlayerStyle.full;
// Configure video complete action: advanceToNext or loop
storyBlockConfiguration.videoCompleteAction =
    VideoPlayerCompleteAction.advanceToNext;
// Indicates if the video player shows share button
storyBlockConfiguration.showShareButton = true;
// Indicates if the video player shows playback button
storyBlockConfiguration.showPlaybackButton = true;
// Indicates if the video player shows mute button
storyBlockConfiguration.showMuteButton = true;
// Specifies if the video detail title should be showed
storyBlockConfiguration.showVideoDetailTitle = true;
StoryBlock(
  source: StoryBlockSource.playlist,
  channel: "your encoded channel id",
  playlist: "your encoded playlist id",
  storyBlockConfiguration: storyBlockConfiguration,
);

// Configure player configuration for openVideoPlayer API
OpenVideoPlayerConfiguration openVideoPlayerConfiguration =
    OpenVideoPlayerConfiguration();
// Configure player style: full or fit
openVideoPlayerConfiguration.playerStyle = VideoPlayerStyle.full;
// Configure video complete action: advanceToNext or loop
openVideoPlayerConfiguration.videoCompleteAction =
    VideoPlayerCompleteAction.advanceToNext;
// Indicates if the video player shows share button
openVideoPlayerConfiguration.showShareButton = true;
// Indicates if the video player shows playback button
openVideoPlayerConfiguration.showPlaybackButton = true;
// Indicates if the video player shows mute button
openVideoPlayerConfiguration.showMuteButton = true;
// Specifies if the video detail title should be showed
openVideoPlayerConfiguration.showVideoDetailTitle = true;
FireworkSDK.getInstance().openVideoPlayer(
  url: url,
  config: openVideoPlayerConfiguration,
);
```
