1import { ExpoConfig } from '@expo/config-types';
2import { XcodeProject } from 'xcode';
3
4import { ConfigPlugin } from '../Plugin.types';
5import { withXcodeProject } from '../plugins/ios-plugins';
6import { addWarningIOS } from '../utils/warnings';
7
8export const withDeviceFamily: ConfigPlugin = (config) => {
9  return withXcodeProject(config, async (config) => {
10    config.modResults = await setDeviceFamily(config, {
11      project: config.modResults,
12    });
13    return config;
14  });
15};
16
17export function getSupportsTablet(config: Pick<ExpoConfig, 'ios'>): boolean {
18  return !!config.ios?.supportsTablet;
19}
20
21export function getIsTabletOnly(config: Pick<ExpoConfig, 'ios'>): boolean {
22  return !!config?.ios?.isTabletOnly;
23}
24
25export function getDeviceFamilies(config: Pick<ExpoConfig, 'ios'>): number[] {
26  const supportsTablet = getSupportsTablet(config);
27  const isTabletOnly = getIsTabletOnly(config);
28
29  if (isTabletOnly && config.ios?.supportsTablet === false) {
30    addWarningIOS(
31      'ios.supportsTablet',
32      `Found contradictory values: \`{ ios: { isTabletOnly: true, supportsTablet: false } }\`. Using \`{ isTabletOnly: true }\`.`
33    );
34  }
35
36  // 1 is iPhone, 2 is iPad
37  if (isTabletOnly) {
38    return [2];
39  } else if (supportsTablet) {
40    return [1, 2];
41  } else {
42    // is iPhone only
43    return [1];
44  }
45}
46
47/**
48 * Wrapping the families in double quotes is the only way to set a value with a comma in it.
49 *
50 * @param deviceFamilies
51 */
52export function formatDeviceFamilies(deviceFamilies: number[]): string {
53  return `"${deviceFamilies.join(',')}"`;
54}
55
56/**
57 * Add to pbxproj under TARGETED_DEVICE_FAMILY
58 */
59export function setDeviceFamily(
60  config: Pick<ExpoConfig, 'ios'>,
61  { project }: { project: XcodeProject }
62): XcodeProject {
63  const deviceFamilies = formatDeviceFamilies(getDeviceFamilies(config));
64
65  const configurations = project.pbxXCBuildConfigurationSection();
66  // @ts-ignore
67  for (const { buildSettings } of Object.values(configurations || {})) {
68    // Guessing that this is the best way to emulate Xcode.
69    // Using `project.addToBuildSettings` modifies too many targets.
70    if (typeof buildSettings?.PRODUCT_NAME !== 'undefined') {
71      if (typeof buildSettings?.TVOS_DEPLOYMENT_TARGET !== 'undefined') {
72        buildSettings.TARGETED_DEVICE_FAMILY = '3';
73      } else {
74        buildSettings.TARGETED_DEVICE_FAMILY = deviceFamilies;
75      }
76    }
77  }
78
79  return project;
80}
81