optimize orientation container position
This commit is contained in:
+8
-3
@@ -68,7 +68,7 @@ private object DrawerLayout {
|
|||||||
val headerToGroupsGap = 10.dp
|
val headerToGroupsGap = 10.dp
|
||||||
val groupRowGap = 12.dp
|
val groupRowGap = 12.dp
|
||||||
val groupsToMenuGap = 10.dp
|
val groupsToMenuGap = 10.dp
|
||||||
val groupButtonWidth = 120.dp
|
// 宽度不固定:按容器宽度两等分,才能和功能菜单的左右边距对齐。设计稿为 120dp。
|
||||||
val groupButtonHeight = 50.dp
|
val groupButtonHeight = 50.dp
|
||||||
val groupButtonGap = 10.dp
|
val groupButtonGap = 10.dp
|
||||||
val menuOuterPaddingH = 8.dp
|
val menuOuterPaddingH = 8.dp
|
||||||
@@ -221,7 +221,10 @@ fun AppDrawer(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
groupRows.forEachIndexed { index, row ->
|
groupRows.forEachIndexed { index, row ->
|
||||||
|
// 必须撑满并等分:固定宽度会被外层 Column 的 CenterHorizontally 居中,
|
||||||
|
// 平板上抽屉变宽后就和下面左对齐的功能菜单差出一截边距。
|
||||||
Row(
|
Row(
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.spacedBy(DrawerLayout.groupButtonGap),
|
horizontalArrangement = Arrangement.spacedBy(DrawerLayout.groupButtonGap),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
@@ -232,7 +235,7 @@ fun AppDrawer(
|
|||||||
selected = currentGroup == group.key,
|
selected = currentGroup == group.key,
|
||||||
onClick = { onGroupSelect(group.key) },
|
onClick = { onGroupSelect(group.key) },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(DrawerLayout.groupButtonWidth)
|
.weight(1f)
|
||||||
.height(DrawerLayout.groupButtonHeight),
|
.height(DrawerLayout.groupButtonHeight),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -313,7 +316,9 @@ private fun GroupButton(
|
|||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = Res.getUri(group.asset.path),
|
model = Res.getUri(group.asset.path),
|
||||||
contentDescription = group.key.displayName,
|
contentDescription = group.key.displayName,
|
||||||
contentScale = ContentScale.FillWidth,
|
// Fit 而非 FillWidth:按钮改为等分后在平板上更宽,
|
||||||
|
// 撑满宽度会把 logo 顶出 50dp 的高度被裁掉。
|
||||||
|
contentScale = ContentScale.Fit,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-27
@@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.offset
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
@@ -467,6 +468,23 @@ fun FullPlayerScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 横屏左栏整体右移一些,不要贴着屏幕边。 */
|
||||||
|
private val LandscapeBodyStartPadding = 48.dp
|
||||||
|
|
||||||
|
/** 横屏封面上限。平板上可用高度能到 280dp 以上,卡住它免得封面占满整栏。 */
|
||||||
|
private val LandscapeCoverMaxSize = 250.dp
|
||||||
|
|
||||||
|
/** 封面区再内缩一点,连带下方同宽的内容一起偏右。 */
|
||||||
|
private val LandscapeCoverInsetStart = 24.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 封面边长未知时先撑满;已知后与封面同宽,左右边缘才对得上。
|
||||||
|
* 偏移量要和封面那边保持一致,否则两者又错开。
|
||||||
|
*/
|
||||||
|
private fun Modifier.coverAlignedWidth(side: Dp?): Modifier =
|
||||||
|
offset(x = LandscapeCoverInsetStart)
|
||||||
|
.then(if (side != null) width(side) else fillMaxWidth())
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LandscapePlayerBody(
|
private fun LandscapePlayerBody(
|
||||||
current: Music?,
|
current: Music?,
|
||||||
@@ -499,12 +517,15 @@ private fun LandscapePlayerBody(
|
|||||||
.statusBarsPadding()
|
.statusBarsPadding()
|
||||||
.navigationBarsPadding()
|
.navigationBarsPadding()
|
||||||
.padding(
|
.padding(
|
||||||
start = safeStart + 28.dp,
|
start = safeStart + LandscapeBodyStartPadding,
|
||||||
end = safeEnd + 28.dp,
|
end = safeEnd + 28.dp,
|
||||||
top = 12.dp,
|
top = 12.dp,
|
||||||
bottom = 16.dp,
|
bottom = 16.dp,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
|
// 封面是受高度约束的正方形,通常比左栏窄;下方内容跟随它的实际边长,
|
||||||
|
// 否则 fillMaxWidth 会让两者左右边缘差出一截。
|
||||||
|
var coverSide by remember { mutableStateOf<Dp?>(null) }
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
.weight(0.42f)
|
.weight(0.42f)
|
||||||
@@ -513,6 +534,7 @@ private fun LandscapePlayerBody(
|
|||||||
.padding(end = 24.dp),
|
.padding(end = 24.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
|
// 收起按钮保持贴左栏边缘,不跟封面对齐。
|
||||||
Row(
|
Row(
|
||||||
Modifier.fillMaxWidth().height(40.dp),
|
Modifier.fillMaxWidth().height(40.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
@@ -529,19 +551,22 @@ private fun LandscapePlayerBody(
|
|||||||
contentDescription = tr("collapse"),
|
contentDescription = tr("collapse"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Box(
|
// 直接用 BoxWithConstraints 承担居中:套在 Box 里再 fillMaxSize 的话,
|
||||||
|
// 外层的 contentAlignment 不起作用,封面会左上角对齐。
|
||||||
|
BoxWithConstraints(
|
||||||
Modifier
|
Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth()
|
||||||
|
.offset(x = LandscapeCoverInsetStart),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
BoxWithConstraints(Modifier.fillMaxSize()) {
|
val side = maxWidth
|
||||||
val side = maxWidth
|
.coerceAtMost(maxHeight)
|
||||||
.coerceAtMost(maxHeight)
|
.coerceAtMost(LandscapeCoverMaxSize)
|
||||||
.coerceAtMost(300.dp)
|
.coerceAtLeast(1.dp)
|
||||||
.coerceAtLeast(1.dp)
|
// 下方内容宽度不影响它们的高度,所以这次写入会立刻收敛。
|
||||||
PlayerCoverArt(music = current, size = side)
|
if (coverSide != side) coverSide = side
|
||||||
}
|
PlayerCoverArt(music = current, size = side)
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
text = current?.musicName ?: tr("not_playing"),
|
text = current?.musicName ?: tr("not_playing"),
|
||||||
@@ -553,9 +578,7 @@ private fun LandscapePlayerBody(
|
|||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
),
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier.coverAlignedWidth(coverSide),
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 12.dp),
|
|
||||||
)
|
)
|
||||||
val artist = current?.artist.orEmpty()
|
val artist = current?.artist.orEmpty()
|
||||||
if (artist.isNotBlank()) {
|
if (artist.isNotBlank()) {
|
||||||
@@ -569,8 +592,8 @@ private fun LandscapePlayerBody(
|
|||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
),
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.coverAlignedWidth(coverSide)
|
||||||
.padding(horizontal = 12.dp, vertical = 2.dp),
|
.padding(vertical = 2.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
PlayerFuncButtons(
|
PlayerFuncButtons(
|
||||||
@@ -582,6 +605,8 @@ private fun LandscapePlayerBody(
|
|||||||
onToggleLove = onToggleLove,
|
onToggleLove = onToggleLove,
|
||||||
onAddSong = onAddSong,
|
onAddSong = onAddSong,
|
||||||
onToggleTranslate = onToggleTranslate,
|
onToggleTranslate = onToggleTranslate,
|
||||||
|
modifier = Modifier.coverAlignedWidth(coverSide),
|
||||||
|
horizontalPadding = 0.dp,
|
||||||
)
|
)
|
||||||
PlayerSeekBar(
|
PlayerSeekBar(
|
||||||
thumbColor = thumbColor,
|
thumbColor = thumbColor,
|
||||||
@@ -589,12 +614,14 @@ private fun LandscapePlayerBody(
|
|||||||
inactiveTrack = inactiveTrack,
|
inactiveTrack = inactiveTrack,
|
||||||
timeColor = timeColor,
|
timeColor = timeColor,
|
||||||
onSeek = { AppContainer.player.seekTo(it) },
|
onSeek = { AppContainer.player.seekTo(it) },
|
||||||
|
modifier = Modifier.coverAlignedWidth(coverSide),
|
||||||
|
trackInset = 0.dp,
|
||||||
|
labelInset = 0.dp,
|
||||||
)
|
)
|
||||||
Row(
|
Row(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.coverAlignedWidth(coverSide)
|
||||||
.height(64.dp)
|
.height(64.dp),
|
||||||
.padding(horizontal = 4.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
@@ -1174,13 +1201,15 @@ private fun PlayerFuncButtons(
|
|||||||
onAddSong: () -> Unit,
|
onAddSong: () -> Unit,
|
||||||
onToggleTranslate: () -> Unit,
|
onToggleTranslate: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
/** 横屏左栏要和控制键左右对齐,传 0。 */
|
||||||
|
horizontalPadding: Dp = 16.dp,
|
||||||
) {
|
) {
|
||||||
val btnBg = Color.Transparent
|
val btnBg = Color.Transparent
|
||||||
val btnIcon = iconTint
|
val btnIcon = iconTint
|
||||||
Row(
|
Row(
|
||||||
modifier
|
modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = horizontalPadding),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
@@ -1287,6 +1316,11 @@ private fun PlayerSeekBar(
|
|||||||
inactiveTrack: Color,
|
inactiveTrack: Color,
|
||||||
timeColor: Color,
|
timeColor: Color,
|
||||||
onSeek: (Long) -> Unit,
|
onSeek: (Long) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
/** 轨道两端留白。横屏左栏要和控制键对齐,传 0。 */
|
||||||
|
trackInset: Dp = 24.dp,
|
||||||
|
/** 时间文字的左右内边距。 */
|
||||||
|
labelInset: Dp = 16.dp,
|
||||||
) {
|
) {
|
||||||
val positionMs = rememberPlayerField { it.positionMs }
|
val positionMs = rememberPlayerField { it.positionMs }
|
||||||
val durationMs = rememberPlayerField { it.durationMs }
|
val durationMs = rememberPlayerField { it.durationMs }
|
||||||
@@ -1296,14 +1330,18 @@ private fun PlayerSeekBar(
|
|||||||
var dragValue by remember { mutableFloatStateOf(0f) }
|
var dragValue by remember { mutableFloatStateOf(0f) }
|
||||||
val display = if (dragging) dragValue else positionMs.toFloat().coerceIn(0f, max)
|
val display = if (dragging) dragValue else positionMs.toFloat().coerceIn(0f, max)
|
||||||
val fraction = (display / max).coerceIn(0f, 1f)
|
val fraction = (display / max).coerceIn(0f, 1f)
|
||||||
|
val thumbRadius = 10.dp
|
||||||
|
// 滑块中心至少离边一个半径,否则贴边时会被画到容器外;
|
||||||
|
// 轨道本身可以贴边,两者的留白因此要分开算。
|
||||||
|
val thumbInset = maxOf(trackInset, thumbRadius)
|
||||||
|
|
||||||
Column(Modifier.fillMaxWidth()) {
|
Column(modifier.fillMaxWidth()) {
|
||||||
BoxWithConstraints(
|
BoxWithConstraints(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(48.dp)
|
.height(48.dp)
|
||||||
.pointerInput(max) {
|
.pointerInput(max, thumbInset) {
|
||||||
val inset = 24.dp.toPx()
|
val inset = thumbInset.toPx()
|
||||||
fun xToValue(x: Float): Float {
|
fun xToValue(x: Float): Float {
|
||||||
val usable = (size.width - inset * 2).coerceAtLeast(1f)
|
val usable = (size.width - inset * 2).coerceAtLeast(1f)
|
||||||
return ((x - inset) / usable).coerceIn(0f, 1f) * max
|
return ((x - inset) / usable).coerceIn(0f, 1f) * max
|
||||||
@@ -1321,11 +1359,9 @@ private fun PlayerSeekBar(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
val thumbRadius = 10.dp
|
|
||||||
val overlayPad = 24.dp
|
|
||||||
val trackHeight = 4.dp
|
val trackHeight = 4.dp
|
||||||
Canvas(Modifier.fillMaxSize()) {
|
Canvas(Modifier.fillMaxSize()) {
|
||||||
val inset = overlayPad.toPx()
|
val inset = trackInset.toPx()
|
||||||
val y = size.height / 2f
|
val y = size.height / 2f
|
||||||
val trackW = (size.width - inset * 2f).coerceAtLeast(0f)
|
val trackW = (size.width - inset * 2f).coerceAtLeast(0f)
|
||||||
val top = y - trackHeight.toPx() / 2f
|
val top = y - trackHeight.toPx() / 2f
|
||||||
@@ -1348,7 +1384,7 @@ private fun PlayerSeekBar(
|
|||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.align(Alignment.CenterStart)
|
.align(Alignment.CenterStart)
|
||||||
.offset(x = overlayPad - thumbRadius + (maxWidth - overlayPad * 2) * fraction)
|
.offset(x = thumbInset - thumbRadius + (maxWidth - thumbInset * 2) * fraction)
|
||||||
.size(thumbRadius * 2)
|
.size(thumbRadius * 2)
|
||||||
.shadow(1.dp, CircleShape)
|
.shadow(1.dp, CircleShape)
|
||||||
.background(thumbColor, CircleShape),
|
.background(thumbColor, CircleShape),
|
||||||
@@ -1357,7 +1393,7 @@ private fun PlayerSeekBar(
|
|||||||
Row(
|
Row(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = labelInset),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
Text(formatMs(display.roundToLong()), color = timeColor, fontSize = 12.sp)
|
Text(formatMs(display.roundToLong()), color = timeColor, fontSize = 12.sp)
|
||||||
|
|||||||
+7
-4
@@ -66,12 +66,15 @@ fun ProvideDesignDensity(content: @Composable () -> Unit) {
|
|||||||
Box(Modifier.fillMaxSize())
|
Box(Modifier.fillMaxSize())
|
||||||
return@CompositionLocalProvider
|
return@CompositionLocalProvider
|
||||||
}
|
}
|
||||||
val heightDp = heightPx / base.density
|
|
||||||
val widthPx = containerPx.width
|
val widthPx = containerPx.width
|
||||||
val isLandscape = widthPx > 0 && widthPx > heightPx
|
val isLandscape = widthPx > 0 && widthPx > heightPx
|
||||||
// 按高度比例缩放;不低于设计尺寸;平板上限 1.35。忽略系统字体缩放(对齐 Flutter textScaler = 1.0)。
|
// 按长边比例缩放;不低于设计尺寸;平板上限 1.35。忽略系统字体缩放(对齐 Flutter textScaler = 1.0)。
|
||||||
// 横屏高度变矮时下限仍是 1,不会按变矮的高度放大或缩小。
|
//
|
||||||
val scale = (heightDp / Const.UI_HEIGHT).coerceIn(1f, 1.35f)
|
// 取长边而不是当前窗口高度,是为了让横竖屏共用同一个 dp 坐标系。
|
||||||
|
// 按窗口高度算的话,横屏高度变成短边,scale 会从上限 1.35 掉回 1,
|
||||||
|
// 同一个 dp 在横屏下物理尺寸要小四分之一。
|
||||||
|
val longestDp = maxOf(widthPx, heightPx) / base.density
|
||||||
|
val scale = (longestDp / Const.UI_HEIGHT).coerceIn(1f, 1.35f)
|
||||||
val scaled = remember(base.density, scale) {
|
val scaled = remember(base.density, scale) {
|
||||||
Density(
|
Density(
|
||||||
density = base.density * scale,
|
density = base.density * scale,
|
||||||
|
|||||||
@@ -13,19 +13,19 @@
|
|||||||
5A902F589276392B4CBC0015 /* HomeWidgetExampleBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30942AA1A2E3A1AB832DD959 /* HomeWidgetExampleBundle.swift */; };
|
5A902F589276392B4CBC0015 /* HomeWidgetExampleBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30942AA1A2E3A1AB832DD959 /* HomeWidgetExampleBundle.swift */; };
|
||||||
76ED3117C0B97CD5572EB808 /* HomeWidgetExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B1CCBD46108D407DF0C9A3 /* HomeWidgetExample.swift */; };
|
76ED3117C0B97CD5572EB808 /* HomeWidgetExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B1CCBD46108D407DF0C9A3 /* HomeWidgetExample.swift */; };
|
||||||
8070A4B4DD1D3DD823A8F923 /* WidgetAppUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0142951DE661E55DC3207327 /* WidgetAppUtils.swift */; };
|
8070A4B4DD1D3DD823A8F923 /* WidgetAppUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0142951DE661E55DC3207327 /* WidgetAppUtils.swift */; };
|
||||||
B7C8D9E0F1A234567890ABCD /* InAppWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F6789012345678 /* InAppWebViewController.swift */; };
|
|
||||||
C8D9E0F1A2B345678901BCDE /* WebViewContentBlocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C3D4E5F67890123456789 /* WebViewContentBlocker.swift */; };
|
|
||||||
A1B2C3D4E5F60718293A4B5C /* BackgroundIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CDB1C6A666078B3272B409 /* BackgroundIntent.swift */; };
|
|
||||||
88ABACE0259DE83261737B99 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E8A7B7E7359EA11B9591 /* SceneDelegate.swift */; };
|
88ABACE0259DE83261737B99 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E8A7B7E7359EA11B9591 /* SceneDelegate.swift */; };
|
||||||
93FF51B22016695CB74F0AD6 /* HostBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6B3C131D45A3E52B69B531 /* HostBridge.swift */; };
|
93FF51B22016695CB74F0AD6 /* HostBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6B3C131D45A3E52B69B531 /* HostBridge.swift */; };
|
||||||
|
A1B2C3D4E5F60718293A4B5C /* BackgroundIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CDB1C6A666078B3272B409 /* BackgroundIntent.swift */; };
|
||||||
A59815941DC5A1C2B9F349CB /* PipScreenManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2016716493FA6F4B6E30EB17 /* PipScreenManager.swift */; };
|
A59815941DC5A1C2B9F349CB /* PipScreenManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2016716493FA6F4B6E30EB17 /* PipScreenManager.swift */; };
|
||||||
|
B7C8D9E0F1A234567890ABCD /* InAppWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F6789012345678 /* InAppWebViewController.swift */; };
|
||||||
C8353E6C8BE98C27FD768A59 /* WidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E6AF7C77765E074EE1C7E597 /* WidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
C8353E6C8BE98C27FD768A59 /* WidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E6AF7C77765E074EE1C7E597 /* WidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
F9A23E2F5F7514E5D6A3D9C0 /* BackgroundIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CDB1C6A666078B3272B409 /* BackgroundIntent.swift */; };
|
C8D9E0F1A2B345678901BCDE /* WebViewContentBlocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C3D4E5F67890123456789 /* WebViewContentBlocker.swift */; };
|
||||||
FA6C12E55F9D41237B4BDAF1 /* CarPlaySceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 310E847101B97B7A36776025 /* CarPlaySceneDelegate.swift */; };
|
|
||||||
FDE52B8D57A097A60A4CF366 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C1F485E0CF8BB70C9DDD2 /* AppDelegate.swift */; };
|
|
||||||
D1E2F3A4B5C60718293A4B02 /* QqShareHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1E2F3A4B5C60718293A4B01 /* QqShareHost.swift */; };
|
D1E2F3A4B5C60718293A4B02 /* QqShareHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1E2F3A4B5C60718293A4B01 /* QqShareHost.swift */; };
|
||||||
D1E2F3A4B5C60718293A4B04 /* TencentOpenAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1E2F3A4B5C60718293A4B03 /* TencentOpenAPI.framework */; };
|
D1E2F3A4B5C60718293A4B04 /* TencentOpenAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1E2F3A4B5C60718293A4B03 /* TencentOpenAPI.framework */; };
|
||||||
D1E2F3A4B5C60718293A4B06 /* TencentOpenApi_IOS_Bundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D1E2F3A4B5C60718293A4B05 /* TencentOpenApi_IOS_Bundle.bundle */; };
|
D1E2F3A4B5C60718293A4B06 /* TencentOpenApi_IOS_Bundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D1E2F3A4B5C60718293A4B05 /* TencentOpenApi_IOS_Bundle.bundle */; };
|
||||||
|
F9A23E2F5F7514E5D6A3D9C0 /* BackgroundIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CDB1C6A666078B3272B409 /* BackgroundIntent.swift */; };
|
||||||
|
FA6C12E55F9D41237B4BDAF1 /* CarPlaySceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 310E847101B97B7A36776025 /* CarPlaySceneDelegate.swift */; };
|
||||||
|
FDE52B8D57A097A60A4CF366 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C1F485E0CF8BB70C9DDD2 /* AppDelegate.swift */; };
|
||||||
I18N0PLIST0BUILD0FILE001 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = I18N0PLIST0VARNT0GROUP01 /* InfoPlist.strings */; };
|
I18N0PLIST0BUILD0FILE001 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = I18N0PLIST0VARNT0GROUP01 /* InfoPlist.strings */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@@ -55,8 +55,6 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
0142951DE661E55DC3207327 /* WidgetAppUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetAppUtils.swift; sourceTree = "<group>"; };
|
0142951DE661E55DC3207327 /* WidgetAppUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetAppUtils.swift; sourceTree = "<group>"; };
|
||||||
A1B2C3D4E5F6789012345678 /* InAppWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppWebViewController.swift; sourceTree = "<group>"; };
|
|
||||||
B2C3D4E5F67890123456789 /* WebViewContentBlocker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewContentBlocker.swift; sourceTree = "<group>"; };
|
|
||||||
1285E8A7B7E7359EA11B9591 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
1285E8A7B7E7359EA11B9591 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
2016716493FA6F4B6E30EB17 /* PipScreenManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipScreenManager.swift; sourceTree = "<group>"; };
|
2016716493FA6F4B6E30EB17 /* PipScreenManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipScreenManager.swift; sourceTree = "<group>"; };
|
||||||
30942AA1A2E3A1AB832DD959 /* HomeWidgetExampleBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetExampleBundle.swift; sourceTree = "<group>"; };
|
30942AA1A2E3A1AB832DD959 /* HomeWidgetExampleBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetExampleBundle.swift; sourceTree = "<group>"; };
|
||||||
@@ -66,20 +64,33 @@
|
|||||||
86038AE1032E284E79B32AD6 /* iosApp.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
86038AE1032E284E79B32AD6 /* iosApp.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
88A292AA7607F14E8C66291E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
88A292AA7607F14E8C66291E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
8B6C1F485E0CF8BB70C9DDD2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
8B6C1F485E0CF8BB70C9DDD2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
A1B2C3D4E5F6789012345678 /* InAppWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppWebViewController.swift; sourceTree = "<group>"; };
|
||||||
|
B2C3D4E5F67890123456789 /* WebViewContentBlocker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewContentBlocker.swift; sourceTree = "<group>"; };
|
||||||
B8B1CCBD46108D407DF0C9A3 /* HomeWidgetExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetExample.swift; sourceTree = "<group>"; };
|
B8B1CCBD46108D407DF0C9A3 /* HomeWidgetExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetExample.swift; sourceTree = "<group>"; };
|
||||||
CE8509E5A49E4A5CAAEB3ADB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
CE8509E5A49E4A5CAAEB3ADB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
E6AF7C77765E074EE1C7E597 /* WidgetExtension.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
F543015C899423D4B01CEB2E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
|
||||||
D1E2F3A4B5C60718293A4B01 /* QqShareHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QqShareHost.swift; sourceTree = "<group>"; };
|
D1E2F3A4B5C60718293A4B01 /* QqShareHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QqShareHost.swift; sourceTree = "<group>"; };
|
||||||
D1E2F3A4B5C60718293A4B03 /* TencentOpenAPI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TencentOpenAPI.framework; path = Vendor/TencentOpenAPI.framework; sourceTree = "<group>"; };
|
D1E2F3A4B5C60718293A4B03 /* TencentOpenAPI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TencentOpenAPI.framework; path = Vendor/TencentOpenAPI.framework; sourceTree = "<group>"; };
|
||||||
D1E2F3A4B5C60718293A4B05 /* TencentOpenApi_IOS_Bundle.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = TencentOpenApi_IOS_Bundle.bundle; path = Vendor/TencentOpenApi_IOS_Bundle.bundle; sourceTree = "<group>"; };
|
D1E2F3A4B5C60718293A4B05 /* TencentOpenApi_IOS_Bundle.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = TencentOpenApi_IOS_Bundle.bundle; path = Vendor/TencentOpenApi_IOS_Bundle.bundle; sourceTree = "<group>"; };
|
||||||
I18N0PLIST0FILE0REF0ZH01 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
D1E2F3A4B5C60718293A4B07 /* iosApp-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "iosApp-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
E6AF7C77765E074EE1C7E597 /* WidgetExtension.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
F543015C899423D4B01CEB2E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
I18N0PLIST0FILE0REF0DE01 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
I18N0PLIST0FILE0REF0EN01 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
I18N0PLIST0FILE0REF0EN01 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
I18N0PLIST0FILE0REF0JA01 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
I18N0PLIST0FILE0REF0JA01 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
I18N0PLIST0FILE0REF0DE01 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
I18N0PLIST0FILE0REF0ZH01 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
D1E2F3A4B5C60718293A4B07 /* iosApp-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "iosApp-Bridging-Header.h"; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
D1E2F3A4B5C60718293A4B08 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
D1E2F3A4B5C60718293A4B04 /* TencentOpenAPI.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
0ECDA917A71DFD183A635257 /* CarPlay */ = {
|
0ECDA917A71DFD183A635257 /* CarPlay */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
@@ -119,15 +130,6 @@
|
|||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
D1E2F3A4B5C60718293A4B09 /* Vendor */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D1E2F3A4B5C60718293A4B03 /* TencentOpenAPI.framework */,
|
|
||||||
D1E2F3A4B5C60718293A4B05 /* TencentOpenApi_IOS_Bundle.bundle */,
|
|
||||||
);
|
|
||||||
name = Vendor;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
5B4BD3733F8124940306FE19 /* pip */ = {
|
5B4BD3733F8124940306FE19 /* pip */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -156,6 +158,15 @@
|
|||||||
path = WidgetExtension;
|
path = WidgetExtension;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D1E2F3A4B5C60718293A4B09 /* Vendor */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D1E2F3A4B5C60718293A4B03 /* TencentOpenAPI.framework */,
|
||||||
|
D1E2F3A4B5C60718293A4B05 /* TencentOpenApi_IOS_Bundle.bundle */,
|
||||||
|
);
|
||||||
|
name = Vendor;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@@ -261,14 +272,6 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
D1E2F3A4B5C60718293A4B08 /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
D1E2F3A4B5C60718293A4B04 /* TencentOpenAPI.framework in Frameworks */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
@@ -289,7 +292,7 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "set -euo pipefail\ncd \"$SRCROOT/..\"\nif [ \"YES\" = \"${OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED:-}\" ]; then\n echo \"Kotlin framework was built by the IDE; syncing Compose resources only\"\n ./gradlew -Pcompose.ios.resources.archs=arm64 :composeApp:syncComposeResourcesForIos --rerun\n exit 0\nfi\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode";
|
shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\nset -euo pipefail\ncd \"$SRCROOT/..\"\nif [ \"YES\" = \"${OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED:-}\" ]; then\n echo \"Kotlin framework was built by the IDE; syncing Compose resources only\"\n ./gradlew -Pcompose.ios.resources.archs=arm64 :composeApp:syncComposeResourcesForIos --rerun\n exit 0\nfi\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode";
|
||||||
};
|
};
|
||||||
C516F4DE7FC107135868F830 /* Verify Widget Extension Embedded */ = {
|
C516F4DE7FC107135868F830 /* Verify Widget Extension Embedded */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
@@ -312,20 +315,6 @@
|
|||||||
};
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
|
||||||
I18N0PLIST0VARNT0GROUP01 /* InfoPlist.strings */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
I18N0PLIST0FILE0REF0ZH01 /* zh-Hans */,
|
|
||||||
I18N0PLIST0FILE0REF0EN01 /* en */,
|
|
||||||
I18N0PLIST0FILE0REF0JA01 /* ja */,
|
|
||||||
I18N0PLIST0FILE0REF0DE01 /* de */,
|
|
||||||
);
|
|
||||||
name = InfoPlist.strings;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
297B59D9CE634556D6007C40 /* Sources */ = {
|
297B59D9CE634556D6007C40 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
@@ -365,6 +354,20 @@
|
|||||||
};
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
I18N0PLIST0VARNT0GROUP01 /* InfoPlist.strings */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
I18N0PLIST0FILE0REF0ZH01 /* zh-Hans */,
|
||||||
|
I18N0PLIST0FILE0REF0EN01 /* en */,
|
||||||
|
I18N0PLIST0FILE0REF0JA01 /* ja */,
|
||||||
|
I18N0PLIST0FILE0REF0DE01 /* de */,
|
||||||
|
);
|
||||||
|
name = InfoPlist.strings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
11814011E7D6EC822BFBC66D /* Release */ = {
|
11814011E7D6EC822BFBC66D /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
@@ -475,12 +478,12 @@
|
|||||||
WebKit,
|
WebKit,
|
||||||
"-lsqlite3",
|
"-lsqlite3",
|
||||||
);
|
);
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "iosApp/iosApp-Bridging-Header.h";
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.zhushenwudi.lovelivemusicplayer;
|
PRODUCT_BUNDLE_IDENTIFIER = com.zhushenwudi.lovelivemusicplayer;
|
||||||
PRODUCT_NAME = LLMP;
|
PRODUCT_NAME = LLMP;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LLMP-M-AD-HOC";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LLMP-M-AD-HOC";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "iosApp/iosApp-Bridging-Header.h";
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
@@ -728,12 +731,12 @@
|
|||||||
WebKit,
|
WebKit,
|
||||||
"-lsqlite3",
|
"-lsqlite3",
|
||||||
);
|
);
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "iosApp/iosApp-Bridging-Header.h";
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.zhushenwudi.lovelivemusicplayer;
|
PRODUCT_BUNDLE_IDENTIFIER = com.zhushenwudi.lovelivemusicplayer;
|
||||||
PRODUCT_NAME = LLMP;
|
PRODUCT_NAME = LLMP;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LLMP-M-DEVELOP";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LLMP-M-DEVELOP";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "iosApp/iosApp-Bridging-Header.h";
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@@ -777,12 +780,12 @@
|
|||||||
WebKit,
|
WebKit,
|
||||||
"-lsqlite3",
|
"-lsqlite3",
|
||||||
);
|
);
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "iosApp/iosApp-Bridging-Header.h";
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.zhushenwudi.lovelivemusicplayer;
|
PRODUCT_BUNDLE_IDENTIFIER = com.zhushenwudi.lovelivemusicplayer;
|
||||||
PRODUCT_NAME = LLMP;
|
PRODUCT_NAME = LLMP;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LLMP-M-RELEASE";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LLMP-M-RELEASE";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "iosApp/iosApp-Bridging-Header.h";
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
|||||||
+45
-2
@@ -1,12 +1,55 @@
|
|||||||
package com.zhushenwudi.lovelivemusicplayer.lyric
|
package com.zhushenwudi.lovelivemusicplayer.lyric
|
||||||
|
|
||||||
|
import kotlinx.cinterop.BooleanVar
|
||||||
|
import kotlinx.cinterop.ExperimentalForeignApi
|
||||||
|
import kotlinx.cinterop.alloc
|
||||||
|
import kotlinx.cinterop.memScoped
|
||||||
|
import kotlinx.cinterop.ptr
|
||||||
|
import kotlinx.cinterop.value
|
||||||
import platform.Foundation.NSBundle
|
import platform.Foundation.NSBundle
|
||||||
|
import platform.Foundation.NSDocumentDirectory
|
||||||
|
import platform.Foundation.NSFileManager
|
||||||
|
import platform.Foundation.NSSearchPathForDirectoriesInDomains
|
||||||
|
import platform.Foundation.NSUserDomainMask
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解锁目录名。Info.plist 开了 UIFileSharingEnabled,
|
||||||
|
* 用户可在「文件」App 的本应用目录下自行新建它。
|
||||||
|
*/
|
||||||
|
private const val UNLOCK_DIR_NAME = "LLMP"
|
||||||
|
|
||||||
actual object PlatformInfo {
|
actual object PlatformInfo {
|
||||||
// iOS 在 EULA 未接受前可能限制日文/罗马音歌词。
|
/**
|
||||||
actual val allowEulaLyric: Boolean = true
|
* iOS 默认只提供中文歌词;Documents 下存在 LLMP 目录才解锁日文/罗马音。
|
||||||
|
*
|
||||||
|
* 刻意只在首次读取时查一次盘:[LyricService.lrcType] 的初值、歌词下载分支、
|
||||||
|
* 以及多处 UI 分支都依赖这个值,运行中途翻转会让它们对不上
|
||||||
|
* (例如 lrcType 停在 0 要显示日文,而日文根本没下载过)。
|
||||||
|
* 用户新建目录后重启应用生效。
|
||||||
|
*/
|
||||||
|
actual val allowEulaLyric: Boolean by lazy { unlockDirExists() }
|
||||||
actual val isIos: Boolean = true
|
actual val isIos: Boolean = true
|
||||||
actual val appVersion: String =
|
actual val appVersion: String =
|
||||||
NSBundle.mainBundle.objectForInfoDictionaryKey("CFBundleShortVersionString") as? String
|
NSBundle.mainBundle.objectForInfoDictionaryKey("CFBundleShortVersionString") as? String
|
||||||
?: ""
|
?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalForeignApi::class)
|
||||||
|
private fun unlockDirExists(): Boolean {
|
||||||
|
val docs = NSSearchPathForDirectoriesInDomains(
|
||||||
|
NSDocumentDirectory,
|
||||||
|
NSUserDomainMask,
|
||||||
|
true,
|
||||||
|
).firstOrNull() as? String ?: return false
|
||||||
|
val path = if (docs.endsWith("/")) {
|
||||||
|
"$docs$UNLOCK_DIR_NAME"
|
||||||
|
} else {
|
||||||
|
"$docs/$UNLOCK_DIR_NAME"
|
||||||
|
}
|
||||||
|
return memScoped {
|
||||||
|
val isDir = alloc<BooleanVar>()
|
||||||
|
// 必须是目录:同名文件不算解锁。
|
||||||
|
NSFileManager.defaultManager.fileExistsAtPath(path, isDirectory = isDir.ptr) &&
|
||||||
|
isDir.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user