Skip to content

Commit

Permalink
Fix RTL language causes OSC to malfunction, #4878 (#4879)
Browse files Browse the repository at this point in the history
This commit will:
- Add initializers to TimeLabelOverflowedStackView,
  TimeLabelOverflowedView and TouchBarPlaySliderCell that set
  userInterfaceLayoutDirection to be leftToRight
- Change MainWindowController.windowDidLoad to set the
  userInterfaceLayoutDirection property of fragControlView and
  oscFloatingTopView to be leftToRight
- Change constraints from leading/trailing to left/right for several OSC
  components to prevent them from moving when a RTL language is used
- Change MainWindowController methods mouseDown and mouseDragged to take
  into account the userInterfaceLayoutDirection setting during playlist
  resizing
- Change ControlBarView.mouseDragged to take into account the
  userInterfaceLayoutDirection setting when repositioning the floating
  OSC
- Rename the play property in the Constants struct to be
  blackRightPointingTriangle
- Add a blackLeftPointingTriangle property to the Constants struct
- Change PlaylistViewController.tableView to use a right or left arrow
  based on the userInterfaceLayoutDirection setting
- Change the language-direction of the pip and volume related icons and
  the playlist icon from Fixed to Left to Right, Mirrors

This adjusts IINA's behavior to match Apple's guidance that video
controls and timeline indicators should not flip in a right-to-left
language. Other controls, such as the volume control and the pip and
playlist buttons are flipped for RTL languages.

This also corrects problems dragging the floating OSC and resizing the
playlist when a right to left language is configured.
  • Loading branch information
low-batt committed May 25, 2024
1 parent 457c2b3 commit 3c165f3
Show file tree
Hide file tree
Showing 17 changed files with 85 additions and 31 deletions.
3 changes: 2 additions & 1 deletion iina/AppData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ struct Constants {
struct String {
static let degree = "°"
static let dot = ""
static let play = "▶︎"
static let blackRightPointingTriangle = "▶︎"
static let blackLeftPointingTriangle = ""
static let videoTimePlaceholder = "--:--:--"
static let trackNone = NSLocalizedString("track.none", comment: "<None>")
static let chapter = "Chapter"
Expand Down
3 changes: 2 additions & 1 deletion iina/Assets.xcassets/Icons/mute.imageset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"images" : [
{
"filename" : "volume-mute.pdf",
"idiom" : "universal"
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
Expand Down
3 changes: 2 additions & 1 deletion iina/Assets.xcassets/Icons/pip.imageset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"images" : [
{
"filename" : "pip.pdf",
"idiom" : "universal"
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"images" : [
{
"filename" : "playing_in_pip.pdf",
"idiom" : "universal"
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
Expand Down
3 changes: 2 additions & 1 deletion iina/Assets.xcassets/Icons/playlist.imageset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"images" : [
{
"filename" : "playlist2.pdf",
"idiom" : "universal"
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
Expand Down
3 changes: 2 additions & 1 deletion iina/Assets.xcassets/Icons/volume-0.imageset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"images" : [
{
"filename" : "volume-0.pdf",
"idiom" : "universal"
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
Expand Down
3 changes: 2 additions & 1 deletion iina/Assets.xcassets/Icons/volume-1.imageset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"images" : [
{
"filename" : "volume-1.pdf",
"idiom" : "universal"
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
Expand Down
3 changes: 2 additions & 1 deletion iina/Assets.xcassets/Icons/volume-2.imageset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"images" : [
{
"filename" : "volume-2.pdf",
"idiom" : "universal"
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
Expand Down
3 changes: 2 additions & 1 deletion iina/Assets.xcassets/Icons/volume.imageset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"images" : [
{
"filename" : "volume.pdf",
"idiom" : "universal"
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
Expand Down
10 changes: 5 additions & 5 deletions iina/Base.lproj/MainWindowController.xib
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@
<customView translatesAutoresizingMaskIntoConstraints="NO" id="BE1-yC-oJL" customClass="TimeLabelOverflowedView" customModule="IINA" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="500" height="29"/>
<subviews>
<slider verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eBP-6g-bAT" customClass="PlaySlider" customModule="IINA" customModuleProvider="target">
<slider verticalHuggingPriority="750" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="eBP-6g-bAT" customClass="PlaySlider" customModule="IINA" customModuleProvider="target">
<rect key="frame" x="48" y="-1" width="404" height="28"/>
<sliderCell key="cell" continuous="YES" refusesFirstResponder="YES" state="on" alignment="left" maxValue="100" doubleValue="50" tickMarkPosition="above" sliderType="linear" id="f1c-xF-8a2" customClass="PlaySliderCell" customModule="IINA" customModuleProvider="target"/>
<connections>
Expand Down Expand Up @@ -592,14 +592,14 @@
</subviews>
<constraints>
<constraint firstItem="10x-bg-xlj" firstAttribute="centerY" secondItem="Yv6-0K-6E4" secondAttribute="centerY" id="4a0-xW-jtL"/>
<constraint firstItem="10x-bg-xlj" firstAttribute="leading" secondItem="Yv6-0K-6E4" secondAttribute="leading" constant="14" id="8Hx-gQ-ez7"/>
<constraint firstItem="10x-bg-xlj" firstAttribute="left" secondItem="Yv6-0K-6E4" secondAttribute="left" constant="14" id="8Hx-gQ-ez7"/>
<constraint firstItem="EIi-qd-glM" firstAttribute="centerY" secondItem="Yv6-0K-6E4" secondAttribute="centerY" id="MRS-GF-0U6"/>
<constraint firstItem="gxw-pJ-Lcg" firstAttribute="centerX" secondItem="Yv6-0K-6E4" secondAttribute="centerX" id="PrE-1U-klM"/>
<constraint firstItem="EIi-qd-glM" firstAttribute="leading" secondItem="gxw-pJ-Lcg" secondAttribute="trailing" constant="24" id="WtE-JF-0m3"/>
<constraint firstItem="EIi-qd-glM" firstAttribute="left" secondItem="gxw-pJ-Lcg" secondAttribute="right" constant="24" id="WtE-JF-0m3"/>
<constraint firstAttribute="height" constant="24" id="Y49-r6-uWL"/>
<constraint firstItem="gxw-pJ-Lcg" firstAttribute="leading" secondItem="10x-bg-xlj" secondAttribute="trailing" constant="24" id="aEy-x5-Ctd"/>
<constraint firstItem="gxw-pJ-Lcg" firstAttribute="left" secondItem="10x-bg-xlj" secondAttribute="right" constant="24" id="aEy-x5-Ctd"/>
<constraint firstItem="gxw-pJ-Lcg" firstAttribute="centerY" secondItem="Yv6-0K-6E4" secondAttribute="centerY" id="dBB-Jk-nlO"/>
<constraint firstAttribute="trailing" secondItem="EIi-qd-glM" secondAttribute="trailing" constant="14" id="enq-Gg-JrN"/>
<constraint firstAttribute="right" secondItem="EIi-qd-glM" secondAttribute="right" constant="14" id="enq-Gg-JrN"/>
</constraints>
<point key="canvasLocation" x="377" y="703"/>
</customView>
Expand Down
27 changes: 15 additions & 12 deletions iina/Base.lproj/MiniPlayerWindowController.xib
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
<binding destination="-2" name="font" keyPath="monospacedFont" id="ivC-kT-hEO"/>
</connections>
</textField>
<slider verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="e3M-Ma-JJM">
<slider verticalHuggingPriority="750" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="e3M-Ma-JJM">
<rect key="frame" x="42" y="5" width="216" height="19"/>
<sliderCell key="cell" continuous="YES" refusesFirstResponder="YES" state="on" alignment="left" maxValue="100" doubleValue="50" tickMarkPosition="above" sliderType="linear" id="Y51-2C-Qcg" customClass="PlaySliderCell" customModule="IINA" customModuleProvider="target"/>
<connections>
Expand All @@ -120,7 +120,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kcj-EY-i9R" customClass="ScrollingTextField" customModule="IINA" customModuleProvider="target">
<textField wantsLayer="YES" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kcj-EY-i9R" customClass="ScrollingTextField" customModule="IINA" customModuleProvider="target">
<rect key="frame" x="109" y="8" width="82" height="14"/>
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Artist - Album" id="Nle-gv-CWY">
<font key="font" metaFont="message" size="11"/>
Expand Down Expand Up @@ -182,6 +182,7 @@
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>

<connections>
<action selector="prevBtnAction:" target="-2" id="BDa-Ku-caU"/>
</connections>
Expand Down Expand Up @@ -210,6 +211,7 @@
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>

<connections>
<action selector="volumeBtnAction:" target="-2" id="ynf-E4-jte"/>
</connections>
Expand All @@ -233,34 +235,34 @@
<constraint firstItem="nSh-lh-jim" firstAttribute="centerY" secondItem="aC9-OK-a4x" secondAttribute="centerY" id="9tz-su-lQa"/>
<constraint firstItem="aC9-OK-a4x" firstAttribute="top" secondItem="cDR-8J-QI7" secondAttribute="top" constant="12" id="Kzm-iJ-Vkp"/>
<constraint firstItem="KFz-Kp-RxC" firstAttribute="centerY" secondItem="a5L-QK-yog" secondAttribute="centerY" id="LaN-Gb-lL9"/>
<constraint firstItem="KFz-Kp-RxC" firstAttribute="leading" secondItem="a5L-QK-yog" secondAttribute="trailing" constant="12" id="PpO-ZM-V3M"/>
<constraint firstItem="KFz-Kp-RxC" firstAttribute="left" secondItem="a5L-QK-yog" secondAttribute="right" constant="12" id="PpO-ZM-V3M"/>
<constraint firstItem="fUy-ap-8fj" firstAttribute="centerY" secondItem="aC9-OK-a4x" secondAttribute="centerY" id="PvJ-Gl-h60"/>
<constraint firstItem="nSh-lh-jim" firstAttribute="leading" secondItem="fUy-ap-8fj" secondAttribute="trailing" constant="20" id="SGi-ju-KtN"/>
<constraint firstItem="nSh-lh-jim" firstAttribute="left" secondItem="fUy-ap-8fj" secondAttribute="right" constant="20" id="SGi-ju-KtN"/>
<constraint firstAttribute="height" constant="48" id="fao-NR-5SG"/>
<constraint firstItem="aC9-OK-a4x" firstAttribute="leading" secondItem="nSh-lh-jim" secondAttribute="trailing" constant="24" id="kCv-eh-zx2"/>
<constraint firstItem="aC9-OK-a4x" firstAttribute="left" secondItem="nSh-lh-jim" secondAttribute="right" constant="24" id="kCv-eh-zx2"/>
<constraint firstItem="998-mn-oHJ" firstAttribute="centerY" secondItem="aC9-OK-a4x" secondAttribute="centerY" id="ldG-Yz-2vC"/>
<constraint firstItem="aC9-OK-a4x" firstAttribute="centerX" secondItem="cDR-8J-QI7" secondAttribute="centerX" constant="2" id="pI1-nE-AtV"/>
<constraint firstItem="a5L-QK-yog" firstAttribute="leading" secondItem="998-mn-oHJ" secondAttribute="trailing" constant="20" id="uSD-MR-I8x"/>
<constraint firstItem="a5L-QK-yog" firstAttribute="left" secondItem="998-mn-oHJ" secondAttribute="right" constant="20" id="uSD-MR-I8x"/>
<constraint firstItem="a5L-QK-yog" firstAttribute="centerY" secondItem="aC9-OK-a4x" secondAttribute="centerY" id="vwZ-Gt-F5N"/>
<constraint firstItem="998-mn-oHJ" firstAttribute="leading" secondItem="aC9-OK-a4x" secondAttribute="trailing" constant="20" id="yL9-7r-6VR"/>
<constraint firstItem="998-mn-oHJ" firstAttribute="left" secondItem="aC9-OK-a4x" secondAttribute="right" constant="20" id="yL9-7r-6VR"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="Zv7-H8-iOq" firstAttribute="leading" secondItem="HdA-I9-dRJ" secondAttribute="leading" id="0RG-9U-PfH"/>
<constraint firstItem="e3M-Ma-JJM" firstAttribute="top" secondItem="HdA-I9-dRJ" secondAttribute="top" constant="50" id="9qE-pN-912"/>
<constraint firstItem="9EY-2T-Ebf" firstAttribute="leading" secondItem="HdA-I9-dRJ" secondAttribute="leading" constant="6" id="CDO-gT-VfY"/>
<constraint firstItem="9EY-2T-Ebf" firstAttribute="left" secondItem="HdA-I9-dRJ" secondAttribute="left" constant="6" id="CDO-gT-VfY"/>
<constraint firstItem="9EY-2T-Ebf" firstAttribute="centerY" secondItem="e3M-Ma-JJM" secondAttribute="centerY" id="HEK-U3-nXU"/>
<constraint firstItem="xAK-xc-Njn" firstAttribute="centerY" secondItem="e3M-Ma-JJM" secondAttribute="centerY" id="IxN-QB-clc"/>
<constraint firstItem="e3M-Ma-JJM" firstAttribute="leading" secondItem="9EY-2T-Ebf" secondAttribute="trailing" constant="6" id="Kq9-D1-FXY"/>
<constraint firstAttribute="trailing" secondItem="xAK-xc-Njn" secondAttribute="trailing" constant="6" id="KxC-bd-MIe"/>
<constraint firstItem="e3M-Ma-JJM" firstAttribute="left" secondItem="9EY-2T-Ebf" secondAttribute="right" constant="6" id="Kq9-D1-FXY"/>
<constraint firstAttribute="right" secondItem="xAK-xc-Njn" secondAttribute="right" constant="6" id="KxC-bd-MIe"/>
<constraint firstAttribute="height" constant="72" id="Nfm-Ob-h4c"/>
<constraint firstItem="9EY-2T-Ebf" firstAttribute="width" secondItem="xAK-xc-Njn" secondAttribute="width" id="UYG-wX-fNd"/>
<constraint firstItem="cDR-8J-QI7" firstAttribute="leading" secondItem="HdA-I9-dRJ" secondAttribute="leading" id="VVS-g3-XqO"/>
<constraint firstItem="cDR-8J-QI7" firstAttribute="top" secondItem="HdA-I9-dRJ" secondAttribute="top" id="Ypa-JG-tiE"/>
<constraint firstItem="Zv7-H8-iOq" firstAttribute="top" secondItem="HdA-I9-dRJ" secondAttribute="top" id="fw5-6p-eNb"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="cDR-8J-QI7" secondAttribute="bottom" constant="24" id="n2O-up-sBQ"/>
<constraint firstItem="xAK-xc-Njn" firstAttribute="leading" secondItem="e3M-Ma-JJM" secondAttribute="trailing" constant="6" id="oEQ-mY-BqT"/>
<constraint firstItem="xAK-xc-Njn" firstAttribute="left" secondItem="e3M-Ma-JJM" secondAttribute="right" constant="6" id="oEQ-mY-BqT"/>
<constraint firstAttribute="trailing" secondItem="cDR-8J-QI7" secondAttribute="trailing" id="uCr-Bo-TON"/>
<constraint firstAttribute="trailing" secondItem="Zv7-H8-iOq" secondAttribute="trailing" id="vmF-Ea-a1k"/>
</constraints>
Expand Down Expand Up @@ -338,6 +340,7 @@
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>

</button>
<button toolTip="Back to video mode" translatesAutoresizingMaskIntoConstraints="NO" id="K7j-vB-FlK">
<rect key="frame" x="2" y="2" width="11" height="11"/>
Expand Down Expand Up @@ -434,6 +437,7 @@
<button translatesAutoresizingMaskIntoConstraints="NO" id="5Og-lg-qvH">
<rect key="frame" x="12" y="8" width="17" height="14"/>
<constraints>
<constraint firstAttribute="width" secondItem="5Og-lg-qvH" secondAttribute="height" multiplier="17:14" id="Sh7-eY-TU8"/>
<constraint firstAttribute="height" constant="14" id="cUj-wp-dxX"/>
</constraints>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="volume" imagePosition="only" alignment="center" alternateImage="mute" refusesFirstResponder="YES" imageScaling="proportionallyUpOrDown" inset="2" id="6jy-7B-dv6">
Expand All @@ -451,7 +455,6 @@
<constraint firstItem="Ene-VG-UYY" firstAttribute="top" secondItem="JoU-Y0-cxJ" secondAttribute="top" constant="8" id="JXq-kB-fdn"/>
<constraint firstItem="MP6-sS-T7f" firstAttribute="leading" secondItem="Ene-VG-UYY" secondAttribute="trailing" constant="8" id="Jfv-7v-xAE"/>
<constraint firstAttribute="trailing" secondItem="MP6-sS-T7f" secondAttribute="trailing" constant="8" id="Nkd-PC-I2B"/>
<constraint firstItem="5Og-lg-qvH" firstAttribute="width" secondItem="5Og-lg-qvH" secondAttribute="height" multiplier="17:14" id="Sh7-eY-TU8"/>
<constraint firstItem="5Og-lg-qvH" firstAttribute="centerY" secondItem="JoU-Y0-cxJ" secondAttribute="centerY" id="U0k-sl-lgS"/>
<constraint firstAttribute="bottom" secondItem="Ene-VG-UYY" secondAttribute="bottom" constant="8" id="Yba-0E-lbi"/>
<constraint firstItem="Ene-VG-UYY" firstAttribute="leading" secondItem="5Og-lg-qvH" secondAttribute="trailing" constant="8" id="agK-tV-GdH"/>
Expand Down
4 changes: 3 additions & 1 deletion iina/ControlBarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ class ControlBarView: NSVisualEffectView {
let yMax = windowFrame.height - frame.height - 25
newOrigin = newOrigin.constrained(to: NSRect(x: 10, y: 0, width: xMax, height: yMax))
// apply position
xConstraint.constant = newOrigin.x + frame.width / 2
let newConstraint = newOrigin.x + frame.width / 2
xConstraint.constant = userInterfaceLayoutDirection == .rightToLeft ?
windowFrame.width - newConstraint : newConstraint
yConstraint.constant = newOrigin.y
}

Expand Down
10 changes: 8 additions & 2 deletions iina/MainWindowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,9 @@ class MainWindowController: PlayerWindowController {
fragControlView.addView(fragControlViewLeftView, in: .center)
fragControlView.addView(fragControlViewMiddleView, in: .center)
fragControlView.addView(fragControlViewRightView, in: .center)
// Video controllers and timeline indicators should not flip in a right-to-left language.
fragControlView.userInterfaceLayoutDirection = .leftToRight
oscFloatingTopView.userInterfaceLayoutDirection = .leftToRight
setupOnScreenController(withPosition: oscPosition)
let buttons = (Preference.array(for: .controlBarToolbarButtons) as? [Int] ?? []).compactMap(Preference.ToolBarButton.init(rawValue:))
setupOSCToolbarButtons(buttons)
Expand Down Expand Up @@ -904,7 +907,9 @@ class MainWindowController: PlayerWindowController {
// playlist resizing
if sideBarStatus == .playlist {
let sf = sideBarView.frame
if NSPointInRect(mousePosRelatedToWindow!, NSMakeRect(sf.origin.x - 4, sf.origin.y, 4, sf.height)) {
let originX = videoView.userInterfaceLayoutDirection == .rightToLeft ?
sf.width + 4 : sf.origin.x - 4
if NSPointInRect(mousePosRelatedToWindow!, NSMakeRect(originX, sf.origin.y, 4, sf.height)) {
isResizingSidebar = true
shouldCallSuper = false
}
Expand All @@ -918,7 +923,8 @@ class MainWindowController: PlayerWindowController {
if isResizingSidebar {
// resize sidebar
let currentLocation = event.locationInWindow
let newWidth = window!.frame.width - currentLocation.x - 2
let newWidth = videoView.userInterfaceLayoutDirection == .rightToLeft ?
currentLocation.x - 2 : window!.frame.width - currentLocation.x - 2
sideBarWidthConstraint.constant = newWidth.clamped(to: PlaylistMinWidth...PlaylistMaxWidth)
} else if !fsState.isFullscreen {
guard !controlBarFloating.isDragging else { return }
Expand Down

0 comments on commit 3c165f3

Please sign in to comment.