<commit_before>// 1. Get first layout pass of grid view so we have a total width and calculate the column width (componentDidMount?).
// 2. Possibly do artwork column layout now, as we can do so based just on the aspect ratio, assuming the text height
//    won't be too different between artworks.
// 3. Get artwork heights by either:
//    - calculating the item size upfront with aspect ratio and a static height for the text labels.
//    - leting the artwork component do a layout pass and calculate its own height based on the column width.
// 4. Update height of grid to encompass all items.

import * as React from "react"
import { Dimensions, ScrollView, StyleSheet, View } from "react-native"
import * as Relay from "react-relay"

import { LayoutEvent } from "../../system/events"
import Spinner from "../spinner"
import Artwork from "./artwork"

const PageSize = 10
const PageEndThreshold = 1000

/**
 * TODOs:
 * - currently all the code assumes column layout
 *   - do no invert aspect ratios in row layout
 * - deal with edge-cases when calculating in which section an artwork should go
 *   - see ARMasonryCollectionViewLayout for details on how to deal with last works sticking out
 *   - the calculation currently only takes into account the size of the image, not if e.g. the sale message is present
 */

interface Props extends ArtistRelayProps, GeneRelayProps {
  /** The direction for the grid, currently only 'column' is supported . */
  sectionDirection: string;

  /** The arity of the number of sections (e.g. columns) to show */
  sectionCount: number;

  /** The inset margin for the whole grid */
  sectionMargin: number;

  /** The per-item margin */
  itemMargin: number;

  /** The artist in question */
  artist: any;

  /** The gene in question */
  gene: any;

  /** The key to get artworks */
  queryKey: any;

  /** Filter for artist artworks */
  filter: any;

  /** Medium for filter artworks */
  medium: string;

  /** Price range for filter artworks */
  priceRange: any;

  /** Sort for filter artworks */
  sort: any;

  /** Relay */
  relay: any;

  /** A callback that is called once all artworks have been queried. */
  onComplete?: () => void;
}

interface State {
  sectionDimension: number
  completed: boolean
  fetchingNextPage: boolean
}

class InfiniteScrollArtworksGrid extends React.Component<Props, State> {
  static defaultProps = {
    sectionDirection: "column",
    sectionCount: Dimensions.get("window").width > 700 ? 3 : 2,
    sectionMargin: 20,
    itemMargin: 20,
  }

  private sentEndForContentLength: null | number

  constructor(props) {
    super(props)

    this.state = {
      sectionDimension: 0,
      completed: false,
      fetchingNextPage: false,
    }

    this.sentEndForContentLength = null
  }

  fetchNextPage() {
    if (this.state.fetchingNextPage || this.state.completed) {
      return
    }
    this.setState({ fetchingNextPage: true })
    this.props.relay.setVariables({
      totalSize: this.props.relay.variables.totalSize + PageSize,
    }, (readyState) => {
      if (readyState.done) {
        this.setState({ fetchingNextPage: false })
        if (!this.props[this.props.queryKey].artworks.pageInfo.hasNextPage && this.props.onComplete) {
          this.props.onComplete()
          this.setState({ completed: true })
        }
      }
    })
  }

  /** A simplified version of the Relay debugging logs for infinite scrolls */
  debugLog(query: string, response?: any, error?: any) {
    // tslint:disable:no-console
    if (__DEV__ && (global as any).originalXMLHttpRequest !== undefined) {
      const groupName = "Infinite scroll request"
      const c: any = console
      c.groupCollapsed(groupName, "color:" + (response ? "black" : "red") + ";")
      console.log("Query:\n", query)
      if (response) {
        console.log("Response:\n", response)
      }
      console.groupEnd()
      if (error) {
        console.error("Error:\n", error)
      }
    }
    // tslint:enable:no-console
  }

  onLayout = (event: LayoutEvent) => {
    const layout = event.nativeEvent.layout
    if (layout.width > 0) {
      // This is the sum of all margins in between sections, so do not count to the right of last column.
      const sectionMargins = this.props.sectionMargin * (this.props.sectionCount - 1)
      this.setState({
        sectionDimension: (layout.width - sectionMargins) / this.props.sectionCount,
      })
    }
  }

  sectionedArtworks() {
    const sectionedArtworks: Artworks[] = []
    const sectionRatioSums: number[] = []
    const queryKey = this.props.queryKey
    const artworks: Artworks = this.props[queryKey].artworks ? this.props[queryKey].artworks.edges.map(({ node }) => node) : []

    for (let i = 0; i < this.props.sectionCount; i++) {
      sectionedArtworks.push([])
      sectionRatioSums.push(0)
    }
    artworks.forEach(artwork => {
      // There are artworks without images and other ‘issues’. Like Force we’re just going to reject those for now.
      // See: https://github.com/artsy/eigen/issues/1667
      //
      if (artwork.image) {
        // Find section with lowest *inverted* aspect ratio sum, which is the shortest column.
        let lowestRatioSum = Number.MAX_VALUE // Start higher, so we always find a
        let sectionIndex: number | null = null
        for (let j = 0; j < sectionRatioSums.length; j++) {
          const ratioSum = sectionRatioSums[j]
          if (ratioSum < lowestRatioSum) {
            sectionIndex = j
            lowestRatioSum = ratioSum
          }<commit_msg>[TypeScript] Small last lint error fix.<commit_after>// 1. Get first layout pass of grid view so we have a total width and calculate the column width (componentDidMount?).
// 2. Possibly do artwork column layout now, as we can do so based just on the aspect ratio, assuming the text height
//    won't be too different between artworks.
// 3. Get artwork heights by either:
//    - calculating the item size upfront with aspect ratio and a static height for the text labels.
//    - leting the artwork component do a layout pass and calculate its own height based on the column width.
// 4. Update height of grid to encompass all items.

import * as React from "react"
import { Dimensions, ScrollView, StyleSheet, View } from "react-native"
import * as Relay from "react-relay"

import { LayoutEvent } from "../../system/events"
import Spinner from "../spinner"
import Artwork from "./artwork"

const PageSize = 10
const PageEndThreshold = 1000

/**
 * TODOs:
 * - currently all the code assumes column layout
 *   - do no invert aspect ratios in row layout
 * - deal with edge-cases when calculating in which section an artwork should go
 *   - see ARMasonryCollectionViewLayout for details on how to deal with last works sticking out
 *   - the calculation currently only takes into account the size of the image, not if e.g. the sale message is present
 */

interface Props extends ArtistRelayProps, GeneRelayProps {
  /** The direction for the grid, currently only 'column' is supported . */
  sectionDirection: string;

  /** The arity of the number of sections (e.g. columns) to show */
  sectionCount: number;

  /** The inset margin for the whole grid */
  sectionMargin: number;

  /** The per-item margin */
  itemMargin: number;

  /** The artist in question */
  artist: any;

  /** The gene in question */
  gene: any;

  /** The key to get artworks */
  queryKey: any;

  /** Filter for artist artworks */
  filter: any;

  /** Medium for filter artworks */
  medium: string;

  /** Price range for filter artworks */
  priceRange: any;

  /** Sort for filter artworks */
  sort: any;

  /** Relay */
  relay: any;

  /** A callback that is called once all artworks have been queried. */
  onComplete?: () => void;
}

interface State {
  sectionDimension: number
  completed: boolean
  fetchingNextPage: boolean
}

class InfiniteScrollArtworksGrid extends React.Component<Props, State> {
  static defaultProps = {
    sectionDirection: "column",
    sectionCount: Dimensions.get("window").width > 700 ? 3 : 2,
    sectionMargin: 20,
    itemMargin: 20,
  }

  private sentEndForContentLength: null | number

  constructor(props) {
    super(props)

    this.state = {
      sectionDimension: 0,
      completed: false,
      fetchingNextPage: false,
    }

    this.sentEndForContentLength = null
  }

  fetchNextPage() {
    if (this.state.fetchingNextPage || this.state.completed) {
      return
    }
    this.setState({ fetchingNextPage: true })
    this.props.relay.setVariables({
      totalSize: this.props.relay.variables.totalSize + PageSize,
    }, (readyState) => {
      if (readyState.done) {
        this.setState({ fetchingNextPage: false })
        if (!this.props[this.props.queryKey].artworks.pageInfo.hasNextPage && this.props.onComplete) {
          this.props.onComplete()
          this.setState({ completed: true })
        }
      }
    })
  }

  /** A simplified version of the Relay debugging logs for infinite scrolls */
  debugLog(query: string, response?: any, error?: any) {
    // tslint:disable:no-console
    if (__DEV__ && (global as any).originalXMLHttpRequest !== undefined) {
      const groupName = "Infinite scroll request"
      const c: any = console
      c.groupCollapsed(groupName, "color:" + (response ? "black" : "red") + ";")
      console.log("Query:\n", query)
      if (response) {
        console.log("Response:\n", response)
      }
      console.groupEnd()
      if (error) {
        console.error("Error:\n", error)
      }
    }
    // tslint:enable:no-console
  }

  onLayout = (event: LayoutEvent) => {
    const layout = event.nativeEvent.layout
    if (layout.width > 0) {
      // This is the sum of all margins in between sections, so do not count to the right of last column.
      const sectionMargins = this.props.sectionMargin * (this.props.sectionCount - 1)
      this.setState({
        sectionDimension: (layout.width - sectionMargins) / this.props.sectionCount,
      })
    }
  }

  sectionedArtworks() {
    const sectionedArtworks: Artworks[] = []
    const sectionRatioSums: number[] = []
    const queryKey = this.props.queryKey
    const artworks: Artworks = this.props[queryKey].artworks ?
      this.props[queryKey].artworks.edges.map(({ node }) => node) : []

    for (let i = 0; i < this.props.sectionCount; i++) {
      sectionedArtworks.push([])
      sectionRatioSums.push(0)
    }
    artworks.forEach(artwork => {
      // There are artworks without images and other ‘issues’. Like Force we’re just going to reject those for now.
      // See: https://github.com/artsy/eigen/issues/1667
      //
      if (artwork.image) {
        // Find section with lowest *inverted* aspect ratio sum, which is the shortest column.
        let lowestRatioSum = Number.MAX_VALUE // Start higher, so we always find a
        let sectionIndex: number | null = null
        for (let j = 0; j < sectionRatioSums.length; j++) {
          const ratioSum = sectionRatioSums[j]
          if (ratioSum < lowestRatioSum) {
            sectionIndex = j
            lowestRatioSum = ratioSum
          }
{'fraction_non_alphanumeric': 0.10822238215185319, 'fraction_numerical': 0.005217704210147535, 'mean_word_length': 2.8215881746304574, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 19, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2889032', 'n_tokens_mistral': 3260, 'n_tokens_neox': 3159, 'n_words': 1099}