diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cea2b5c59..0afa268f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,9 +75,21 @@ jobs: platform_name: Windows (ARM) build: 'pnpm tauri build --target aarch64-pc-windows-msvc' - platform: 'macos-26' - platform_name: iOS - build: 'pnpm tauri ios build --export-method app-store-connect' - build_dev: 'pnpm tauri ios build --export-method debugging' + platform_name: iOS (TestFlight) + platform_type: iOS + build: 'pnpm tauri ios build --export-method app-store-connect --build-number 1' + disable_offers: 'false' + disable_options: 'false' + disable_swap: 'false' + ipa_name: Sage_TestFlight + - platform: 'macos-26' + platform_name: iOS (App Store) + platform_type: iOS + build: 'pnpm tauri ios build --export-method app-store-connect --build-number 2' + disable_offers: 'true' + disable_options: 'true' + disable_swap: 'true' + ipa_name: Sage_AppStore - platform: 'macos-15' platform_name: Android build: 'pnpm tauri android build' @@ -90,7 +102,7 @@ jobs: run: rustup target add x86_64-apple-darwin - name: Add aarch64-apple-ios - if: matrix.platform_name == 'iOS' + if: matrix.platform_type == 'iOS' run: rustup target add aarch64-apple-ios - name: Add aarch64-pc-windows-msvc @@ -150,19 +162,19 @@ jobs: run: pnpm install - name: Save API key to file - if: matrix.platform_name == 'MacOS' || matrix.platform_name == 'iOS' + if: matrix.platform_name == 'MacOS' || matrix.platform_type == 'iOS' run: | mkdir -p ~/private_keys echo -n '${{ secrets.APPLE_API_SECRET_KEY }}' > ~/private_keys/AuthKey_${{ secrets.APPLE_API_KEY_ID }}.p8 - name: Setup Xcode - if: matrix.platform_name == 'iOS' + if: matrix.platform_type == 'iOS' uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: '26.5' - name: Verify Xcode SDK - if: matrix.platform_name == 'iOS' + if: matrix.platform_type == 'iOS' run: | xcodebuild -version xcrun --sdk iphoneos --show-sdk-version @@ -173,16 +185,25 @@ jobs: # On MacOS we only notarize on tagged releases # On iOS we need these secrets as well to do code signing - name: Build with secrets - if: ${{ (matrix.platform_name == 'MacOS' && startsWith(github.event.ref, 'refs/tags/v')) || matrix.platform_name == 'iOS' }} - run: ${{ startsWith(github.event.ref, 'refs/tags/v') && matrix.build || matrix.build_dev || matrix.build }} + if: ${{ (matrix.platform_name == 'MacOS' && startsWith(github.event.ref, 'refs/tags/v')) || matrix.platform_type == 'iOS' }} + run: ${{ matrix.build }} env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_KEY_PATH: ~/private_keys/AuthKey_${{ secrets.APPLE_API_KEY_ID }}.p8 + VITE_DISABLE_OFFERS: ${{ matrix.disable_offers }} + VITE_DISABLE_OPTIONS: ${{ matrix.disable_options }} + VITE_DISABLE_SWAP: ${{ matrix.disable_swap }} CI: true + - name: Preserve iOS IPA + if: matrix.platform_type == 'iOS' + run: | + mkdir -p artifacts/ios + cp src-tauri/gen/apple/build/arm64/Sage.ipa "artifacts/ios/${{ matrix.ipa_name }}.ipa" + # On Android we need to use the NDK environment variables. - name: Build with NDK if: matrix.platform_name == 'Android' @@ -195,7 +216,7 @@ jobs: # We don't currently do signing on other platforms - name: Build without secrets - if: ${{ !((matrix.platform_name == 'MacOS' && startsWith(github.event.ref, 'refs/tags/v')) || matrix.platform_name == 'iOS' || matrix.platform_name == 'Android') }} + if: ${{ !((matrix.platform_name == 'MacOS' && startsWith(github.event.ref, 'refs/tags/v')) || matrix.platform_type == 'iOS' || matrix.platform_name == 'Android') }} run: ${{ matrix.build }} env: CI: true @@ -334,21 +355,21 @@ jobs: # iOS - name: Upload IPA (iOS) uses: actions/upload-artifact@v4 - if: matrix.platform_name == 'iOS' + if: matrix.platform_type == 'iOS' with: - name: Sage_iOS.ipa - path: src-tauri/gen/apple/build/arm64/*.ipa + name: ${{ matrix.ipa_name }}.ipa + path: artifacts/ios/${{ matrix.ipa_name }}.ipa - name: Release (iOS) uses: softprops/action-gh-release@v2 - if: matrix.platform_name == 'iOS' && startsWith(github.event.ref, 'refs/tags/v') + if: matrix.platform_type == 'iOS' && startsWith(github.event.ref, 'refs/tags/v') with: files: | - src-tauri/gen/apple/build/arm64/*.ipa + artifacts/ios/${{ matrix.ipa_name }}.ipa - - name: Upload to App Store (or TestFlight) - if: matrix.platform_name == 'iOS' && startsWith(github.event.ref, 'refs/tags/v') - run: xcrun altool --upload-app --type ios --file "src-tauri/gen/apple/build/arm64/Sage.ipa" --apiKey $APPLE_API_KEY_ID --apiIssuer $APPLE_API_ISSUER + - name: Upload iOS build to App Store Connect + if: matrix.platform_type == 'iOS' && startsWith(github.event.ref, 'refs/tags/v') + run: xcrun altool --upload-app --type ios --file "artifacts/ios/${{ matrix.ipa_name }}.ipa" --apiKey $APPLE_API_KEY_ID --apiIssuer $APPLE_API_ISSUER env: APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} diff --git a/crates/sage-wallet/src/wallet/offer/take_offer.rs b/crates/sage-wallet/src/wallet/offer/take_offer.rs index 05808907c..67b3d55e8 100644 --- a/crates/sage-wallet/src/wallet/offer/take_offer.rs +++ b/crates/sage-wallet/src/wallet/offer/take_offer.rs @@ -95,13 +95,8 @@ impl Wallet { .iter() .map(|coin_spend| coin_spend.coin.coin_id()) .collect_vec(); - self.select_spends_excluding( - &mut ctx, - &mut spends, - &actions, - &offer_input_coin_ids, - ) - .await?; + self.select_spends_excluding(&mut ctx, &mut spends, &actions, &offer_input_coin_ids) + .await?; // Reset DIDs and reveal trade prices let mut royalty_nft_count = 0; diff --git a/src/components/CoinList.tsx b/src/components/CoinList.tsx index fe8029205..244013e9d 100644 --- a/src/components/CoinList.tsx +++ b/src/components/CoinList.tsx @@ -1,3 +1,4 @@ +import { offersEnabled } from '@/lib/features'; import { spacescanCoinUrl } from '@/lib/urls'; import { formatTimestamp, fromMojos } from '@/lib/utils'; import { t } from '@lingui/core/macro'; @@ -334,7 +335,9 @@ const SpentCell = ({ row }: { row: Row }) => : row.original.transaction_id ? t`Pending...` : row.original.offer_id - ? t`Locked in offer` + ? offersEnabled + ? t`Locked in offer` + : t`Locked` : ''; // Wrapper components to eliminate remaining inline arrow functions diff --git a/src/components/MultiSelectActions.tsx b/src/components/MultiSelectActions.tsx index b7168cc90..21a356c4d 100644 --- a/src/components/MultiSelectActions.tsx +++ b/src/components/MultiSelectActions.tsx @@ -2,6 +2,7 @@ import { commands, NftRecord, TransactionResponse } from '@/bindings'; import { CustomError } from '@/contexts/ErrorContext'; import { useErrors } from '@/hooks/useErrors'; import useOfferStateWithDefault from '@/hooks/useOfferStateWithDefault'; +import { offersEnabled } from '@/lib/features'; import { toMojos } from '@/lib/utils'; import { useWalletState } from '@/state'; import { t } from '@lingui/core/macro'; @@ -242,50 +243,54 @@ export function MultiSelectActions({ - + {offersEnabled && ( + <> + - { - e.stopPropagation(); + { + e.stopPropagation(); - const newNfts = [...offerState.offered.nfts]; - let addedCount = 0; + const newNfts = [...offerState.offered.nfts]; + let addedCount = 0; - for (const item of selected) { - if (newNfts.includes(item)) { - continue; - } + for (const item of selected) { + if (newNfts.includes(item)) { + continue; + } - newNfts.push(item); - addedCount++; - } + newNfts.push(item); + addedCount++; + } - setOfferState({ - offered: { - ...offerState.offered, - nfts: newNfts, - }, - }); + setOfferState({ + offered: { + ...offerState.offered, + nfts: newNfts, + }, + }); - const nfts = addedCount === 1 ? t`NFT` : t`NFTs`; - const message = - addedCount > 0 - ? t`Added ${addedCount} ${nfts} to offer` - : t`Selected NFTs are already in the offer`; - toast.success(message, { - onClick: () => navigate('/offers/make'), - }); + const nfts = addedCount === 1 ? t`NFT` : t`NFTs`; + const message = + addedCount > 0 + ? t`Added ${addedCount} ${nfts} to offer` + : t`Selected NFTs are already in the offer`; + toast.success(message, { + onClick: () => navigate('/offers/make'), + }); - onConfirm(); - }} - aria-label={t`Add ${selectedCount} selected NFTs to offer`} - > - + onConfirm(); + }} + aria-label={t`Add ${selectedCount} selected NFTs to offer`} + > + + + )} diff --git a/src/components/Nav.tsx b/src/components/Nav.tsx index 03d9e8a39..7b653ca4c 100644 --- a/src/components/Nav.tsx +++ b/src/components/Nav.tsx @@ -4,10 +4,10 @@ import { TooltipTrigger, } from '@/components/ui/tooltip'; import { usePeers } from '@/hooks/usePeers'; +import { offersEnabled, optionsEnabled, swapEnabled } from '@/lib/features'; import { logoutAndUpdateState, useWalletState } from '@/state'; import { t } from '@lingui/core/macro'; import { Trans } from '@lingui/react/macro'; -import { platform } from '@tauri-apps/plugin-os'; import { ArrowDownUp, ArrowLeftRight, @@ -33,8 +33,6 @@ interface NavProps { export function TopNav({ isCollapsed }: NavProps) { const className = isCollapsed ? 'h-5 w-5' : 'h-4 w-4'; - const isIos = platform() === 'ios'; - return (