<commit_before>/* global __TARGET__ */
import React, { useContext } from 'react'
import { useDispatch } from 'react-redux'
import { models, useClient } from 'cozy-client'
import { SharingContext, ShareModal } from 'cozy-sharing'
import { ModalContext } from 'drive/lib/ModalContext'
import keyBy from 'lodash/keyBy'
import Alerter from 'cozy-ui/transpiled/react/Alerter'

import DeleteConfirm from 'drive/web/modules/drive/DeleteConfirm'
import MoveModal from 'drive/web/modules/move/MoveModal'
import { EditDocumentQualification } from 'cozy-scanner'
import ShareMenuItem from 'drive/web/modules/drive/ShareMenuItem'
import MakeAvailableOfflineMenuItem from 'drive/web/modules/drive/MakeAvailableOfflineMenuItem'

import { isIOSApp } from 'cozy-device-helper'
import { startRenamingAsync } from 'drive/web/modules/drive/rename'
import { isReferencedByAlbum } from 'drive/web/modules/drive/files' // TODO move to cozy-client models
import { forceFileDownload } from 'cozy-stack-client/dist/utils'

const { file: fileModel } = models
const { isFile, isDirectory } = fileModel

const isAnyFileReferencedByAlbum = files => {
  for (let i = 0, l = files.length; i < l; ++i) {
    if (isReferencedByAlbum(files[i])) return true
  }
  return false
}

const downloadFiles = async (files, client) => {
  if (files.length === 1 && !isDirectory(files[0])) {
    const file = files[0]

    try {
      const downloadURL = await client
        .collection('io.cozy.files')
        .getDownloadLinkById(file.id)
      const filename = file.name

      forceFileDownload(
        `${client.getStackClient().uri}${downloadURL}?Dl=1`,
        filename
      )
    } catch (error) {
      const isMissingFile = error.status === 404
      const errorMessage = isMissingFile
        ? 'error.download_file.missing'
        : 'error.download_file.offline'
      Alerter.error(errorMessage)
      throw error
    }
  } else {
    const ids = files.map(f => f.id)
    const href = await client
      .collection('io.cozy.files')
      .getArchiveLinkByIds(ids)
    const fullpath = `${client.getStackClient().uri}${href}`
    forceFileDownload(fullpath, 'files.zip')
  }
}

const isAlreadyInTrash = err => {
  const reasons = err.reason !== undefined ? err.reason.errors : undefined
  if (reasons) {
    for (const reason of reasons) {
      if (reason.detail === 'File or directory is already in the trash') {
        return true
      }
    }
  }
  return false
}

const trashFiles = async (files, client) => {
  try {
    for (const file of files) {
      await client.collection('io.cozy.files').destroy(file)
      client.collection('io.cozy.permissions').revokeSharingLink(file)
    }

    Alerter.success('alert.trash_file_success')
  } catch (err) {
    if (!isAlreadyInTrash(err)) {
      Alerter.error('alert.try_again')
    }
  }
}

const useActions = (documentId, { canMove } = {}) => {
  const { pushModal, popModal } = useContext(ModalContext)
  const { hasWriteAccess, refresh } = useContext(SharingContext)
  const client = useClient()
  const dispatch = useDispatch()

  const isWritable = hasWriteAccess(documentId)

  const actions = {
    share: {
      icon: 'share',
      displayCondition: selection => isWritable && selection.length === 1,
      action: selected =>
        pushModal(
          <ShareModal
            document={selected[0]}
            documentType="Files"
            sharingDesc={selected[0].name}
            onClose={popModal}
          />
        ),
      Component: function ShareMenuItemInMenu({ files, ...rest }) {
        return <ShareMenuItem docId={files[0].id} {...rest} />
      }
    },
    download:
      __TARGET__ === 'mobile'
        ? {
            icon: 'download',
            displayCondition: files => {
              if (isIOSApp()) return files.length === 1 && isFile(files[0])
              return files.reduce(
                (onlyFiles, file) => onlyFiles && isFile(file),
                true
              )
            },
            action: files => alert('not implemented') //dispatch(exportFilesNative(files)),
          }
        : {
            icon: 'download',
            action: files => downloadFiles(files, client)
          },
    trash: {
      icon: 'trash',<commit_msg>feat: Download offline action<commit_after>/* global __TARGET__ */
import React, { useContext } from 'react'
import { useDispatch } from 'react-redux'
import { models, useClient } from 'cozy-client'
import { SharingContext, ShareModal } from 'cozy-sharing'
import { ModalContext } from 'drive/lib/ModalContext'
import keyBy from 'lodash/keyBy'
import Alerter from 'cozy-ui/transpiled/react/Alerter'

import DeleteConfirm from 'drive/web/modules/drive/DeleteConfirm'
import MoveModal from 'drive/web/modules/move/MoveModal'
import { EditDocumentQualification } from 'cozy-scanner'
import ShareMenuItem from 'drive/web/modules/drive/ShareMenuItem'
import MakeAvailableOfflineMenuItem from 'drive/web/modules/drive/MakeAvailableOfflineMenuItem'

import { isIOSApp, isIOS } from 'cozy-device-helper'
import { startRenamingAsync } from 'drive/web/modules/drive/rename'
import { isReferencedByAlbum } from 'drive/web/modules/drive/files' // TODO move to cozy-client models
import { forceFileDownload } from 'cozy-stack-client/dist/utils'
import { saveFileWithCordova } from 'drive/mobile/lib/filesystem'

const { file: fileModel } = models
const { isFile, isDirectory } = fileModel

const isAnyFileReferencedByAlbum = files => {
  for (let i = 0, l = files.length; i < l; ++i) {
    if (isReferencedByAlbum(files[i])) return true
  }
  return false
}

const downloadFileError = error => {
  const isMissingFile = error.status === 404
  return isMissingFile
    ? 'error.download_file.missing'
    : 'error.download_file.offline'
}

const downloadFiles = async (files, client) => {
  if (files.length === 1 && !isDirectory(files[0])) {
    const file = files[0]

    try {
      const downloadURL = await client
        .collection('io.cozy.files')
        .getDownloadLinkById(file.id)
      const filename = file.name

      forceFileDownload(
        `${client.getStackClient().uri}${downloadURL}?Dl=1`,
        filename
      )
    } catch (error) {
      Alerter.error(downloadFileError(error))
      throw error
    }
  } else {
    const ids = files.map(f => f.id)
    const href = await client
      .collection('io.cozy.files')
      .getArchiveLinkByIds(ids)
    const fullpath = `${client.getStackClient().uri}${href}`
    forceFileDownload(fullpath, 'files.zip')
  }
}

const isAlreadyInTrash = err => {
  const reasons = err.reason !== undefined ? err.reason.errors : undefined
  if (reasons) {
    for (const reason of reasons) {
      if (reason.detail === 'File or directory is already in the trash') {
        return true
      }
    }
  }
  return false
}

const trashFiles = async (files, client) => {
  try {
    for (const file of files) {
      await client.collection('io.cozy.files').destroy(file)
      client.collection('io.cozy.permissions').revokeSharingLink(file)
    }

    Alerter.success('alert.trash_file_success')
  } catch (err) {
    if (!isAlreadyInTrash(err)) {
      Alerter.error('alert.try_again')
    }
  }
}

export const exportFilesNative = async (files, client, filename) => {
  const downloadAllFiles = files.map(async file => {
    const response = await client
      .collection('io.cozy.files')
      .fetchFileContent(file)

    const blob = await response.blob()
    const filenameToUse = filename ? filename : file.name
    const localFile = await saveFileWithCordova(blob, filenameToUse)
    return localFile.nativeURL
  })

  try {
    Alerter.info('alert.preparing', {
      duration: Math.min(downloadAllFiles.length * 2000, 6000)
    })
    const urls = await Promise.all(downloadAllFiles)
    if (urls.length === 1 && isIOS()) {
      //TODO
      //It seems that files: is not well supported on iOS. url seems to work well
      //at with one file. Need to check when severals
      window.plugins.socialsharing.shareWithOptions(
        {
          url: urls[0]
        },
        result => {
          if (result.completed === true) {
            Alerter.success('mobile.download.success')
          }
        },
        error => {
          throw error
        }
      )
    } else {
      window.plugins.socialsharing.shareWithOptions(
        {
          files: urls
        },
        null,
        error => {
          throw error
        }
      )
    }
  } catch (error) {
    Alerter.error(downloadFileError(error))
  }
}

    try {
      Alerter.info('alert.preparing', {
        duration: Math.min(downloadAllFiles.length * 2000, 6000)
      })
      const urls = await Promise.all(downloadAllFiles)
      if (urls.length === 1 && isIOS()) {
        //TODO
        //It seems that files: is not well supported on iOS. url seems to work well
        //at with one file. Need to check when severals
        window.plugins.socialsharing.shareWithOptions(
          {
            url: urls[0]
          },
          result => {
            if (result.completed === true) {
              Alerter.success('mobile.download.success')
            }
          },
          error => {
            throw error
          }
        )
      } else {
        window.plugins.socialsharing.shareWithOptions(
          {
            files: urls
          },
          null,
          error => {
            throw error
          }
        )
      }
    } catch (error) {
      Alerter.error(downloadFileError(error))
    }
  }
}

const useActions = (documentId, { canMove } = {}) => {
  const { pushModal, popModal } = useContext(ModalContext)
  const { hasWriteAccess, refresh } = useContext(SharingContext)
  const client = useClient()
  const dispatch = useDispatch()

  const isWritable = hasWriteAccess(documentId)

  const actions = {
    share: {
      icon: 'share',
      displayCondition: selection => isWritable && selection.length === 1,
      action: selected =>
        pushModal(
          <ShareModal
            document={selected[0]}
            documentType="Files"
            sharingDesc={selected[0].name}
            onClose={popModal}
          />
        ),
      Component: function ShareMenuItemInMenu({ files, ...rest }) {
        return <ShareMenuItem docId={files[0].id} {...rest} />
      }
    },
    download:
      __TARGET__ === 'mobile'
        ? {
            icon: 'download',
            displayCondition: files => {
              if (isIOSApp()) return files.length === 1 && isFile(files[0])
              return files.reduce(
                (onlyFiles, file) => onlyFiles && isFile(file),
                true
              )
            },
            action: files => exportFilesNative(files, client)
          }
        : {
            icon: 'download',
            action: files => downloadFiles(files, client)
          },
    trash: {
      icon: 'trash',
{'fraction_non_alphanumeric': 0.12126779972439136, 'fraction_numerical': 0.0044097381717960495, 'mean_word_length': 2.473516273133376, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 38, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4619824', 'n_tokens_mistral': 3263, 'n_tokens_neox': 3194, 'n_words': 739}