Skip to content

Commit

Permalink
Media list view iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
dasdranagon committed Jan 8, 2025
1 parent 936977b commit 524ac5e
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 5 deletions.
1 change: 1 addition & 0 deletions example/android/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<string name="feature_links">Links</string>
<string name="feature_location">Location</string>
<string name="feature_media">Media</string>
<string name="feature_media_sound">Sound</string>
<string name="feature_permissions">Permissions</string>
<string name="feature_system">System</string>
<string name="feature_beacons">Beacons</string>
Expand Down
4 changes: 4 additions & 0 deletions example/ios/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
93EC5B31E0ADDED3225B15C9 /* Color+Color.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F49DA13243DC3767266475 /* Color+Color.generated.swift */; };
9481F22DC3CFE170CE894584 /* KeyboardManager.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F34DFA21F534655B6FD3D03 /* KeyboardManager.generated.swift */; };
BC5100D52D2C3B2200095938 /* sound.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = BC5100D42D2C3B2200095938 /* sound.mp3 */; };
BC5100D92D2EB42700095938 /* MediaListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5100D82D2EB42700095938 /* MediaListViewController.swift */; };
C77C23B538A4DFB02C0E0773 /* LazyView.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095989173871C8CDA70C49E1 /* LazyView.generated.swift */; };
C9555693B015ADE12795997D /* NavigationBarColor.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C9189D92DAF37F9815ECFDC /* NavigationBarColor.generated.swift */; };
D0F06CF9B138426F812F3B0B /* ShapeView.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9730959B8EF5B66133F731D2 /* ShapeView.generated.swift */; };
Expand Down Expand Up @@ -221,6 +222,7 @@
A1AD210B87A46DBD057A7D28 /* Navigation.generated.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Navigation.generated.swift; sourceTree = "<group>"; };
A8678F48E60D40E6AB06177C /* LifecycleViewModel.generated.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = LifecycleViewModel.generated.swift; sourceTree = "<group>"; };
BC5100D42D2C3B2200095938 /* sound.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = sound.mp3; sourceTree = "<group>"; };
BC5100D82D2EB42700095938 /* MediaListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaListViewController.swift; sourceTree = "<group>"; };
CCF6BD3638095E5452785FF3 /* KalugaLabel+SwiftUI.generated.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = "KalugaLabel+SwiftUI.generated.swift"; sourceTree = "<group>"; };
D7A59766D89528BA5F4327BD /* Subject.generated.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Subject.generated.swift; sourceTree = "<group>"; };
EA317627E5725424F6B7569C /* KalugaDate+Extensions.generated.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = "KalugaDate+Extensions.generated.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -265,6 +267,7 @@
children = (
BC5100D42D2C3B2200095938 /* sound.mp3 */,
2025CA2A29C9FC480037DF68 /* MediaViewController.swift */,
BC5100D82D2EB42700095938 /* MediaListViewController.swift */,
);
path = Media;
sourceTree = "<group>";
Expand Down Expand Up @@ -721,6 +724,7 @@
buildActionMask = 2147483647;
files = (
20BB9E7729642FEB0096E836 /* PermissionViewController.swift in Sources */,
BC5100D92D2EB42700095938 /* MediaListViewController.swift in Sources */,
207AB7A72A74002E00B4A30F /* BluetoothListDeviceView.swift in Sources */,
205747572397C9C400CDE25E /* KeyboardManagerViewController.swift in Sources */,
74671D1F8F6A31F1DD3F7912 /* AppDelegate.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions example/ios/Demo/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"feature_keyboard" = "Keyboard";
"feature_location" = "Location";
"feature_media" = "Media";
"feature_media_sound" = "Sound";
"feature_permissions" = "Permissions";
"feature_links" = "Links";
"feature_beacons" = "Beacons";
Expand Down
53 changes: 51 additions & 2 deletions example/ios/Demo/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@
<segue destination="VPE-Hp-Qc9" kind="show" identifier="showLinks" id="KlM-G9-P6y"/>
<segue destination="NRf-rC-nl1" kind="show" identifier="showSystem" id="IT2-HT-9Hz"/>
<segue destination="2CB-DJ-Qmw" kind="show" identifier="showBeacons" id="jYU-Fd-PgO"/>
<segue destination="tFZ-So-TfL" kind="show" identifier="showMedia" id="b9n-hF-4CR"/>
<segue destination="cE5-oS-pNm" kind="push" identifier="showMediaList" id="Mcr-Xc-6GI"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="L6W-Hz-iOT" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
Expand Down Expand Up @@ -1735,7 +1735,56 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dLs-Ax-S7X" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3466.666666666667" y="1072.7678571428571"/>
<point key="canvasLocation" x="4196" y="1073"/>
</scene>
<!--Media List View Controller-->
<scene sceneID="61u-W6-GcX">
<objects>
<tableViewController id="cE5-oS-pNm" customClass="MediaListViewController" customModule="Demo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" id="wEY-5V-qfO">
<rect key="frame" x="0.0" y="0.0" width="414" height="886"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MediaListCell" id="JZk-IA-xVn" customClass="MediaListCell" customModule="Demo" customModuleProvider="target">
<rect key="frame" x="0.0" y="50" width="414" height="61.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JZk-IA-xVn" id="mpl-i7-Cvw">
<rect key="frame" x="0.0" y="0.0" width="414" height="61.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="E29-TD-cTR">
<rect key="frame" x="20" y="20" width="374" height="21.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="E29-TD-cTR" firstAttribute="leading" secondItem="mpl-i7-Cvw" secondAttribute="leading" constant="20" symbolic="YES" id="czr-sV-aue"/>
<constraint firstAttribute="trailing" secondItem="E29-TD-cTR" secondAttribute="trailing" constant="20" symbolic="YES" id="rGo-Ji-rb0"/>
<constraint firstItem="E29-TD-cTR" firstAttribute="top" secondItem="mpl-i7-Cvw" secondAttribute="top" constant="20" symbolic="YES" id="s34-fE-5Jo"/>
<constraint firstAttribute="bottom" secondItem="E29-TD-cTR" secondAttribute="bottom" constant="20" symbolic="YES" id="tdT-2T-vIV"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="label" destination="E29-TD-cTR" id="lOP-um-cIE"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="cE5-oS-pNm" id="TXo-dP-Wf2"/>
<outlet property="delegate" destination="cE5-oS-pNm" id="VGG-KP-5Gc"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="SVV-XL-E9r"/>
<connections>
<segue destination="tFZ-So-TfL" kind="push" identifier="showMedia" id="5T9-9N-DDd"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="IVw-qt-NeT" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3386" y="1073"/>
</scene>
</scenes>
<resources>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ private extension FeatureListNavigationAction {
)
}
case is FeatureListNavigationAction.Location: return NavigationSpec.Segue(identifier: "showLocation")
case is FeatureListNavigationAction.Media: return NavigationSpec.Segue(identifier: "showMedia")
case is FeatureListNavigationAction.Media: return NavigationSpec.Segue(identifier: "showMediaList")
case is FeatureListNavigationAction.Permissions: return NavigationSpec.Segue(identifier: "showPermissions")
case is FeatureListNavigationAction.PlatformSpecific: return NavigationSpec.Segue(identifier: "showPlatformSpecific")
case is FeatureListNavigationAction.Resources: return NavigationSpec.Push(animated: true) {
Expand Down
95 changes: 95 additions & 0 deletions example/ios/Demo/Media/MediaListViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// Copyright 2025 Splendo Consulting B.V. The Netherlands
//
// 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.
//

import UIKit
import KalugaExampleShared

class MediaListViewController: UITableViewController {

private lazy var navigator: ViewControllerNavigator<MediaListNavigationAction> = ViewControllerNavigator(parentVC: self) { action in
NavigationSpec.Segue(identifier: action.segueKey)
}

private lazy var viewModel = MediaListViewModel(navigator: navigator)
private var lifecycleManager: LifecycleManager!

private var media = [String]()
private var onSelected: ((Int) -> Void)?

deinit {
lifecycleManager.unbind()
}

override func viewDidLoad() {
super.viewDidLoad()

title = "feature_media".localized()

lifecycleManager = viewModel.addLifecycleManager(parent: self) { [weak self] in
guard let viewModel = self?.viewModel else { return [] }
return [
viewModel.media.observeInitialized { next in
let media = next ?? []
self?.media = media.map { ($0 as? Media)?.title ?? "" }
self?.onSelected = { (index: Int) in
if let media = media[index] as? Media {
viewModel.onMediaSelected(media: media)
}
}
self?.tableView.reloadData()
}
]
}
}

override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return media.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableView.dequeueTypedReusableCell(withIdentifier: MediaListCell.Const.identifier, for: indexPath) { (cell: MediaListCell) in
cell.label.text = media[indexPath.row]
}
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
_ = onSelected?(indexPath.row)
tableView.deselectRow(at: indexPath, animated: true)
}
}

class MediaListCell: UITableViewCell {

enum Const {
static let identifier = "MediaListCell"
}

@IBOutlet weak var label: UILabel!
}

private extension MediaListNavigationAction {
var segueKey: String {
switch self {
case is MediaListNavigationAction.Media: return "showMedia"
case is MediaListNavigationAction.Sound: return "showSound"
default: return ""
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright 2025 Splendo Consulting B.V. The Netherlands
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 com.splendo.kaluga.example.shared.viewmodel.media

import com.splendo.kaluga.architecture.navigation.NavigationAction
import com.splendo.kaluga.architecture.navigation.Navigator
import com.splendo.kaluga.architecture.observable.observableOf
import com.splendo.kaluga.architecture.viewmodel.NavigatingViewModel
import com.splendo.kaluga.resources.localized

sealed class MediaListNavigationAction : NavigationAction<Nothing>(null) {

data object Media : MediaListNavigationAction()
data object Sound : MediaListNavigationAction()
}

enum class Media(private val titleKey: String) {
MEDIA("feature_media"),
SOUND("feature_media_sound"),
;

val title: String get() = titleKey.localized()
}

class MediaListViewModel(navigator: Navigator<MediaListNavigationAction>) : NavigatingViewModel<MediaListNavigationAction>(navigator) {

val media = observableOf(Media.values().toList())

fun onMediaSelected(media: Media) {
navigator.navigate(
when (media) {
Media.MEDIA -> MediaListNavigationAction.Media
Media.SOUND -> MediaListNavigationAction.Sound
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,12 @@ import com.splendo.kaluga.base.text.format
import com.splendo.kaluga.example.shared.stylable.ButtonStyles
import com.splendo.kaluga.media.BaseMediaManager
import com.splendo.kaluga.media.DefaultMediaPlayer
import com.splendo.kaluga.media.DefaultSoundPlayer
import com.splendo.kaluga.media.MediaPlayer
import com.splendo.kaluga.media.MediaSource
import com.splendo.kaluga.media.MediaSurfaceProvider
import com.splendo.kaluga.media.PlaybackError
import com.splendo.kaluga.media.PlaybackState
import com.splendo.kaluga.media.Resolution
import com.splendo.kaluga.media.SoundPlayer
import com.splendo.kaluga.media.duration
import com.splendo.kaluga.media.isVideo
import com.splendo.kaluga.media.mediaSourceFromUrl
Expand Down

0 comments on commit 524ac5e

Please sign in to comment.