Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Open sidebar
VideoLAN
VLC-iOS
Commits
d066b469
Commit
d066b469
authored
Jul 31, 2018
by
Soomin Lee
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Disable DnD
parent
3fdc850a
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
505 additions
and
504 deletions
+505
-504
Sources/VLCDragAndDropManager.swift
Sources/VLCDragAndDropManager.swift
+475
-474
Sources/VLCMediaSubcategory+VLCDragAndDrop.swift
Sources/VLCMediaSubcategory+VLCDragAndDrop.swift
+30
-30
No files found.
Sources/VLCDragAndDropManager.swift
View file @
d066b469
...
...
@@ -33,478 +33,479 @@ protocol VLCDragAndDropManagerDelegate: NSObjectProtocol {
}
@available
(
iOS
11.0
,
*
)
class
VLCDragAndDropManager
<
T
>
:
NSObject
,
UICollectionViewDragDelegate
,
UITableViewDragDelegate
,
UICollectionViewDropDelegate
,
UITableViewDropDelegate
,
UIDropInteractionDelegate
{
let
utiTypeIdentifiers
:
[
String
]
=
VLCDragAndDropManager
.
supportedTypeIdentifiers
()
var
subcategory
:
VLCMediaSubcategoryModel
<
T
>
/// Returns the supported type identifiers that VLC can process.
/// It fetches the identifiers in LSItemContentTypes from all the CFBundleDocumentTypes in the info.plist.
/// Video, Audio and Subtitle formats
///
/// - Returns: Array of UTITypeIdentifiers
private
class
func
supportedTypeIdentifiers
()
->
[
String
]
{
var
typeIdentifiers
:
[
String
]
=
[]
if
let
documents
=
Bundle
.
main
.
infoDictionary
?[
"CFBundleDocumentTypes"
]
as?
[[
String
:
Any
]]
{
for
item
in
documents
{
if
let
value
=
item
[
"LSItemContentTypes"
]
as?
[
String
]
{
typeIdentifiers
.
append
(
contentsOf
:
value
)
}
}
}
return
typeIdentifiers
}
@available
(
*
,
unavailable
,
message
:
"use init(category:)"
)
override
init
()
{
fatalError
()
}
init
(
subcategory
:
VLCMediaSubcategoryModel
<
T
>
)
{
self
.
subcategory
=
subcategory
super
.
init
()
}
// MARK: - TableView
func
tableView
(
_
tableView
:
UITableView
,
canHandle
session
:
UIDropSession
)
->
Bool
{
return
canHandleDropSession
(
session
:
session
)
}
func
tableView
(
_
tableView
:
UITableView
,
itemsForAddingTo
session
:
UIDragSession
,
at
indexPath
:
IndexPath
,
point
:
CGPoint
)
->
[
UIDragItem
]
{
return
dragItems
(
forIndexPath
:
indexPath
)
}
func
tableView
(
_
tableView
:
UITableView
,
itemsForBeginning
session
:
UIDragSession
,
at
indexPath
:
IndexPath
)
->
[
UIDragItem
]
{
return
dragItems
(
forIndexPath
:
indexPath
)
}
func
tableView
(
_
tableView
:
UITableView
,
dropSessionDidUpdate
session
:
UIDropSession
,
withDestinationIndexPath
destinationIndexPath
:
IndexPath
?)
->
UITableViewDropProposal
{
let
operation
=
dropOperation
(
hasActiveDrag
:
tableView
.
hasActiveDrag
,
firstSessionItem
:
session
.
items
.
first
,
withDestinationIndexPath
:
destinationIndexPath
)
return
UITableViewDropProposal
(
operation
:
operation
,
intent
:
.
insertIntoDestinationIndexPath
)
}
func
tableView
(
_
tableView
:
UITableView
,
performDropWith
coordinator
:
UITableViewDropCoordinator
)
{
let
section
=
tableView
.
numberOfSections
-
1
let
row
=
tableView
.
numberOfRows
(
inSection
:
section
)
let
destinationPath
=
coordinator
.
destinationIndexPath
??
IndexPath
(
row
:
row
,
section
:
section
)
for
item
in
coordinator
.
items
{
let
itemProvider
=
item
.
dragItem
.
itemProvider
// we're not gonna handle moving of folders
if
let
sourceItem
=
item
.
dragItem
.
localObject
,
fileIsCollection
(
file
:
sourceItem
as
AnyObject
)
{
continue
}
if
fileIsFolder
(
atIndexPath
:
destinationPath
)
{
// handle dropping onto a folder
addDragItem
(
tableView
:
tableView
,
dragItem
:
item
,
toFolderAt
:
destinationPath
)
continue
}
if
item
.
sourceIndexPath
!=
nil
{
// element within VLC
moveItem
(
tableView
:
tableView
,
item
:
item
,
toIndexPath
:
destinationPath
)
continue
}
// Element dragging from another App
let
placeholder
=
UITableViewDropPlaceholder
(
insertionIndexPath
:
destinationPath
,
reuseIdentifier
:
VLCPlaylistTableViewCell
.
cellIdentifier
(),
rowHeight
:
VLCPlaylistTableViewCell
.
heightOfCell
())
let
placeholderContext
=
coordinator
.
drop
(
item
.
dragItem
,
to
:
placeholder
)
createFileWith
(
itemProvider
:
itemProvider
)
{
[
weak
self
]
file
,
error
in
guard
let
strongSelf
=
self
else
{
return
}
if
let
file
=
file
{
placeholderContext
.
commitInsertion
()
{
insertionIndexPath
in
strongSelf
.
subcategory
.
dragAndDropManagerInsertItem
(
manager
:
strongSelf
,
item
:
file
,
atIndexPath
:
insertionIndexPath
)
}
}
if
let
error
=
error
as?
DropError
{
strongSelf
.
handleError
(
error
:
error
,
itemProvider
:
item
.
dragItem
.
itemProvider
)
placeholderContext
.
deletePlaceholder
()
}
}
}
}
private
func
inFolder
()
->
Bool
{
return
subcategory
.
dragAndDropManagerCurrentSelection
(
manager
:
self
)
as?
MLLabel
!=
nil
}
private
func
moveItem
(
tableView
:
UITableView
,
item
:
UITableViewDropItem
,
toIndexPath
destinationPath
:
IndexPath
)
{
if
let
mlFile
=
item
.
dragItem
.
localObject
as?
MLFile
,
!
mlFile
.
labels
.
isEmpty
&&
!
inFolder
()
{
tableView
.
performBatchUpdates
({
tableView
.
insertRows
(
at
:
[
destinationPath
],
with
:
.
automatic
)
subcategory
.
dragAndDropManagerInsertItem
(
manager
:
self
,
item
:
mlFile
,
atIndexPath
:
destinationPath
)
subcategory
.
dragAndDropManagerRemoveFileFromFolder
(
manager
:
self
,
file
:
mlFile
)
},
completion
:
nil
)
}
}
private
func
addDragItem
(
tableView
:
UITableView
,
dragItem
item
:
UITableViewDropItem
,
toFolderAt
index
:
IndexPath
)
{
if
let
sourcepath
=
item
.
sourceIndexPath
{
// local file that just needs to be moved
tableView
.
performBatchUpdates
({
if
let
file
=
subcategory
.
dragAndDropManagerRequestsFile
(
manager
:
self
,
atIndexPath
:
sourcepath
)
as?
MLFile
{
tableView
.
deleteRows
(
at
:
[
sourcepath
],
with
:
.
automatic
)
addFile
(
file
:
file
,
toFolderAt
:
index
)
subcategory
.
dragAndDropManagerDeleteItem
(
manager
:
self
,
atIndexPath
:
sourcepath
)
}
},
completion
:
nil
)
return
}
// file from other app
createFileWith
(
itemProvider
:
item
.
dragItem
.
itemProvider
)
{
[
weak
self
]
file
,
error
in
if
let
strongSelf
=
self
,
let
file
=
file
{
strongSelf
.
addFile
(
file
:
file
,
toFolderAt
:
index
)
}
}
}
// MARK: - Collectionview
func
collectionView
(
_
collectionView
:
UICollectionView
,
canHandle
session
:
UIDropSession
)
->
Bool
{
return
canHandleDropSession
(
session
:
session
)
}
func
collectionView
(
_
collectionView
:
UICollectionView
,
itemsForBeginning
session
:
UIDragSession
,
at
indexPath
:
IndexPath
)
->
[
UIDragItem
]
{
return
dragItems
(
forIndexPath
:
indexPath
)
}
func
collectionView
(
_
collectionView
:
UICollectionView
,
itemsForAddingTo
session
:
UIDragSession
,
at
indexPath
:
IndexPath
,
point
:
CGPoint
)
->
[
UIDragItem
]
{
return
dragItems
(
forIndexPath
:
indexPath
)
}
func
collectionView
(
_
collectionView
:
UICollectionView
,
dropSessionDidUpdate
session
:
UIDropSession
,
withDestinationIndexPath
destinationIndexPath
:
IndexPath
?)
->
UICollectionViewDropProposal
{
let
operation
=
dropOperation
(
hasActiveDrag
:
collectionView
.
hasActiveDrag
,
firstSessionItem
:
session
.
items
.
first
,
withDestinationIndexPath
:
destinationIndexPath
)
return
UICollectionViewDropProposal
(
operation
:
operation
,
intent
:
.
insertIntoDestinationIndexPath
)
}
func
collectionView
(
_
collectionView
:
UICollectionView
,
performDropWith
coordinator
:
UICollectionViewDropCoordinator
)
{
let
section
=
collectionView
.
numberOfSections
-
1
let
row
=
collectionView
.
numberOfItems
(
inSection
:
section
)
let
destinationPath
=
coordinator
.
destinationIndexPath
??
IndexPath
(
row
:
row
,
section
:
section
)
for
item
in
coordinator
.
items
{
if
let
sourceItem
=
item
.
dragItem
.
localObject
,
fileIsCollection
(
file
:
sourceItem
as
AnyObject
)
{
// We're not handling moving of Collection
continue
}
if
fileIsFolder
(
atIndexPath
:
destinationPath
)
{
// handle dropping onto a folder
addDragItem
(
collectionView
:
collectionView
,
dragItem
:
item
,
toFolderAt
:
destinationPath
)
continue
}
if
item
.
sourceIndexPath
!=
nil
{
// element within VLC
moveItem
(
collectionView
:
collectionView
,
item
:
item
,
toIndexPath
:
destinationPath
)
continue
}
// Element from another App
let
placeholder
=
UICollectionViewDropPlaceholder
(
insertionIndexPath
:
destinationPath
,
reuseIdentifier
:
VLCPlaylistCollectionViewCell
.
cellIdentifier
())
let
placeholderContext
=
coordinator
.
drop
(
item
.
dragItem
,
to
:
placeholder
)
createFileWith
(
itemProvider
:
item
.
dragItem
.
itemProvider
)
{
[
weak
self
]
file
,
error
in
guard
let
strongSelf
=
self
else
{
return
}
if
let
file
=
file
{
placeholderContext
.
commitInsertion
()
{
insertionIndexPath
in
strongSelf
.
subcategory
.
dragAndDropManagerInsertItem
(
manager
:
strongSelf
,
item
:
file
,
atIndexPath
:
insertionIndexPath
)
}
}
if
let
error
=
error
as?
DropError
{
strongSelf
.
handleError
(
error
:
error
,
itemProvider
:
item
.
dragItem
.
itemProvider
)
placeholderContext
.
deletePlaceholder
()
}
}
}
}
private
func
moveItem
(
collectionView
:
UICollectionView
,
item
:
UICollectionViewDropItem
,
toIndexPath
destinationPath
:
IndexPath
)
{
if
let
mlFile
=
item
.
dragItem
.
localObject
as?
MLFile
,
!
mlFile
.
labels
.
isEmpty
&&
!
inFolder
()
{
collectionView
.
performBatchUpdates
({
collectionView
.
insertItems
(
at
:
[
destinationPath
])
subcategory
.
dragAndDropManagerInsertItem
(
manager
:
self
,
item
:
mlFile
,
atIndexPath
:
destinationPath
)
subcategory
.
dragAndDropManagerRemoveFileFromFolder
(
manager
:
self
,
file
:
mlFile
)
},
completion
:
nil
)
}
}
private
func
addDragItem
(
collectionView
:
UICollectionView
,
dragItem
item
:
UICollectionViewDropItem
,
toFolderAt
index
:
IndexPath
)
{
if
let
sourcepath
=
item
.
sourceIndexPath
{
// local file that just needs to be moved
collectionView
.
performBatchUpdates
({
if
let
file
=
subcategory
.
dragAndDropManagerRequestsFile
(
manager
:
self
,
atIndexPath
:
sourcepath
)
as?
MLFile
{
collectionView
.
deleteItems
(
at
:
[
sourcepath
])
addFile
(
file
:
file
,
toFolderAt
:
index
)
subcategory
.
dragAndDropManagerDeleteItem
(
manager
:
self
,
atIndexPath
:
sourcepath
)
}
},
completion
:
nil
)
}
else
{
// file from other app
createFileWith
(
itemProvider
:
item
.
dragItem
.
itemProvider
)
{
[
weak
self
]
file
,
error
in
if
let
strongSelf
=
self
,
let
file
=
file
{
strongSelf
.
addFile
(
file
:
file
,
toFolderAt
:
index
)
}
}
}
}
// MARK: - DropInteractionDelegate for EmptyView
func
dropInteraction
(
_
interaction
:
UIDropInteraction
,
canHandle
session
:
UIDropSession
)
->
Bool
{
return
canHandleDropSession
(
session
:
session
)
}
func
dropInteraction
(
_
interaction
:
UIDropInteraction
,
sessionDidUpdate
session
:
UIDropSession
)
->
UIDropProposal
{
return
UIDropProposal
(
operation
:
.
copy
)
}
func
dropInteraction
(
_
interaction
:
UIDropInteraction
,
performDrop
session
:
UIDropSession
)
{
for
item
in
session
.
items
{
createFileWith
(
itemProvider
:
item
.
itemProvider
)
{
[
weak
self
]
_
,
error
in
if
let
error
=
error
as?
DropError
{
self
?
.
handleError
(
error
:
error
,
itemProvider
:
item
.
itemProvider
)
}
// no need to handle the file case since the libraryVC updates itself after getting a file
}
}
}
// MARK: - Shared Methods
// Checks if the session has items conforming to typeidentifiers
private
func
canHandleDropSession
(
session
:
UIDropSession
)
->
Bool
{
if
session
.
localDragSession
!=
nil
{
return
true
}
return
session
.
hasItemsConforming
(
toTypeIdentifiers
:
utiTypeIdentifiers
)
}
/// Returns a drop operation type
///
/// - Parameters:
/// - hasActiveDrag: State if the drag started within the app
/// - item: UIDragItem from session
/// - Returns: UIDropOperation
private
func
dropOperation
(
hasActiveDrag
:
Bool
,
firstSessionItem
item
:
AnyObject
?,
withDestinationIndexPath
destinationIndexPath
:
IndexPath
?)
->
UIDropOperation
{
let
inAlbum
=
subcategory
.
dragAndDropManagerCurrentSelection
(
manager
:
self
)
as?
MLAlbum
!=
nil
let
inShow
=
subcategory
.
dragAndDropManagerCurrentSelection
(
manager
:
self
)
as?
MLShow
!=
nil
// you can move files into a folder or copy from anothr app into a folder
if
fileIsFolder
(
atIndexPath
:
destinationIndexPath
)
{
// no dragging entire shows and albums into folders
if
let
dragItem
=
item
,
let
mlFile
=
dragItem
.
localObject
as?
MLFile
,
mlFile
.
isAlbumTrack
()
||
mlFile
.
isShowEpisode
()
{
return
.
forbidden
}
return
hasActiveDrag
?
.
move
:
.
copy
}
// you can't reorder
if
inFolder
()
{
return
hasActiveDrag
?
.
forbidden
:
.
copy
}
// you can't reorder in or drag into an Album or Show
if
inAlbum
||
inShow
{
return
.
cancel
}
// we're dragging a file out of a folder
if
let
dragItem
=
item
,
let
mlFile
=
dragItem
.
localObject
as?
MLFile
,
!
mlFile
.
labels
.
isEmpty
{
return
.
copy
}
// no reorder from another app into the top layer
return
hasActiveDrag
?
.
forbidden
:
.
copy
}
/// show an Alert when dropping failed
///
/// - Parameters:
/// - error: the type of error that happend
/// - itemProvider: the itemProvider to retrieve the suggestedName
private
func
handleError
(
error
:
DropError
,
itemProvider
:
NSItemProvider
)
{
let
message
:
String
let
filename
=
itemProvider
.
suggestedName
??
NSLocalizedString
(
"THIS_FILE"
,
comment
:
""
)
switch
error
.
kind
{
case
.
loadFileRepresentationFailed
:
message
=
String
(
format
:
NSLocalizedString
(
"NOT_SUPPORTED_FILETYPE"
,
comment
:
""
),
filename
)
case
.
moveFileToDocuments
:
message
=
String
(
format
:
NSLocalizedString
(
"FILE_EXISTS"
,
comment
:
""
),
filename
)
}
let
alert
=
UIAlertController
(
title
:
NSLocalizedString
(
"ERROR"
,
comment
:
""
),
message
:
message
,
preferredStyle
:
.
alert
)
alert
.
addAction
(
UIAlertAction
(
title
:
NSLocalizedString
(
"OK"
,
comment
:
""
),
style
:
.
default
,
handler
:
nil
))
UIApplication
.
shared
.
keyWindow
?
.
rootViewController
?
.
present
(
alert
,
animated
:
true
,
completion
:
nil
)
}
private
func
fileIsFolder
(
atIndexPath
indexPath
:
IndexPath
?)
->
Bool
{
if
let
indexPath
=
indexPath
{
let
file
=
subcategory
.
dragAndDropManagerRequestsFile
(
manager
:
self
,
atIndexPath
:
indexPath
)
return
file
as?
MLLabel
!=
nil
}
return
false
}
private
func
fileIsCollection
(
file
:
Any
?)
->
Bool
{
let
isFolder
=
file
as?
MLLabel
!=
nil
let
isAlbum
=
file
as?
MLAlbum
!=
nil
let
isShow
=
file
as?
MLShow
!=
nil
return
isFolder
||
isAlbum
||
isShow
}
private
func
fileIsCollection
(
atIndexPath
indexPath
:
IndexPath
?)
->
Bool
{
if
let
indexPath
=
indexPath
{
if
let
file
=
subcategory
.
dragAndDropManagerRequestsFile
(
manager
:
self
,
atIndexPath
:
indexPath
)
{
return
fileIsCollection
(
file
:
file
)
}
}
return
false
}
// creating dragItems for the file at indexpath
private
func
dragItems
(
forIndexPath
indexPath
:
IndexPath
)
->
[
UIDragItem
]
{
if
let
file
=
subcategory
.
dragAndDropManagerRequestsFile
(
manager
:
self
,
atIndexPath
:
indexPath
)
{
if
fileIsCollection
(
atIndexPath
:
indexPath
)
{
return
dragItemsforCollection
(
file
:
file
)
}
return
dragItem
(
fromFile
:
file
)
}
assert
(
false
,
"we can't generate a dragfile if the delegate can't return a file "
)
return
[]
}
/// Iterates over the items of a collection to create dragitems.
/// Since we're not storing collections as folders we have to provide single files
///
/// - Parameter file: Can be of type MLAlbum, MLLabel or MLShow
/// - Returns: An array of UIDragItems
private
func
dragItemsforCollection
(
file
:
Any
)
->
[
UIDragItem
]
{
var
dragItems
=
[
UIDragItem
]()
var
set
=
Set
<
AnyHashable
>
()
if
let
folder
=
file
as?
MLLabel
{
set
=
folder
.
files
}
else
if
let
album
=
file
as?
MLAlbum
{
for
track
in
album
.
tracks
{
if
let
mlfile
=
(
track
as?
MLAlbumTrack
)?
.
files
.
first
{
_
=
set
.
insert
(
mlfile
)
}
}
}
else
if
let
show
=
file
as?
MLShow
{
for
episode
in
show
.
episodes
{
if
let
mlfile
=
(
episode
as?
MLShowEpisode
)?
.
files
{
set
=
set
.
union
(
mlfile
)
}
}
}
else
{
assert
(
false
,
"can't get dragitems from a file that is not a collection"
)
}
for
convertibleFile
in
set
{
if
let
mlfile
=
convertibleFile
as?
MLFile
,
let
item
=
dragItem
(
fromFile
:
mlfile
)
.
first
{
dragItems
.
append
(
item
)
}
}
return
dragItems
}
//Provides an item for other applications
private
func
dragItem
(
fromFile
file
:
Any
)
->
[
UIDragItem
]
{
guard
let
file
=
mlFile
(
from
:
file
as
AnyObject
),
let
path
=
file
.
url
else
{
assert
(
false
,
"can't create a dragitem if there is no file or the file has no url"
)
return
[]
}
let
data
=
try
?
Data
(
contentsOf
:
path
,
options
:
.
mappedIfSafe
)
let
itemProvider
=
NSItemProvider
()
itemProvider
.
suggestedName
=
path
.
lastPathComponent
// maybe use UTTypeForFileURL
if
let
identifiers
=
try
?
path
.
resourceValues
(
forKeys
:
[
.
typeIdentifierKey
]),
let
identifier
=
identifiers
.
typeIdentifier
{
// here we can show progress
itemProvider
.
registerDataRepresentation
(
forTypeIdentifier
:
identifier
,
visibility
:
.
all
)
{
completion
->
Progress
?
in
completion
(
data
,
nil
)
return
nil
}
let
dragitem
=
UIDragItem
(
itemProvider
:
itemProvider
)
dragitem
.
localObject
=
file
return
[
dragitem
]
}
assert
(
false
,
"we can't provide a typeidentifier"
)
return
[]
}
private
func
mlFile
(
from
file
:
AnyObject
)
->
MLFile
?
{
if
let
episode
=
file
as?
MLShowEpisode
,
let
convertedfile
=
episode
.
files
.
first
as?
MLFile
{
return
convertedfile
}
if
let
track
=
file
as?
MLAlbumTrack
,
let
convertedfile
=
track
.
files
.
first
as?
MLFile
{
return
convertedfile
}
if
let
convertedfile
=
file
as?
MLFile
{
return
convertedfile
}
return
nil
}
private
func
addFile
(
file
:
MLFile
,
toFolderAt
folderIndex
:
IndexPath
)
{
let
label
=
subcategory
.
dragAndDropManagerRequestsFile
(
manager
:
self
,
atIndexPath
:
folderIndex
)
as!
MLLabel
DispatchQueue
.
main
.
async
{
_
=
label
.
files
.
insert
(
file
)
file
.
labels
=
[
label
]
file
.
folderTrackNumber
=
NSNumber
(
integerLiteral
:
label
.
files
.
count
-
1
)
}
}
/// try to create a file from the dropped item
///
/// - Parameters:
/// - itemProvider: itemprovider which is used to load the files from
/// - completion: callback with the successfully created file or error if it failed
private
func
createFileWith
(
itemProvider
:
NSItemProvider
,
completion
:
@escaping
((
MLFile
?,
Error
?)
->
Void
))
{
itemProvider
.
loadFileRepresentation
(
forTypeIdentifier
:
kUTTypeData
as
String
)
{
[
weak
self
]
(
url
,
error
)
in
guard
let
strongSelf
=
self
else
{
return
}
guard
let
url
=
url
else
{
DispatchQueue
.
main
.
async
{
completion
(
nil
,
DropError
(
kind
:
.
loadFileRepresentationFailed
))
}
return
}
// returns nil for local session but this should also not be called for a local session
guard
let
destinationURL
=
strongSelf
.
moveFileToDocuments
(
fromURL
:
url
)
else
{
DispatchQueue
.
main
.
async
{
completion
(
nil
,
DropError
(
kind
:
.
moveFileToDocuments
))
}
return
}
DispatchQueue
.
global
(
qos
:
.
background
)
.
async
{
let
sharedlib
=
MLMediaLibrary
.
sharedMediaLibrary
()
as?
MLMediaLibrary
sharedlib
?
.
addFilePaths
([
destinationURL
.
path
])
if
let
file
=
MLFile
.
file
(
for
:
destinationURL
)
.
first
as?
MLFile
{
DispatchQueue
.
main
.
async
{
// we dragged into a folder
if
let
selection
=
strongSelf
.
subcategory
.
dragAndDropManagerCurrentSelection
(
manager
:
strongSelf
)
as?
MLLabel
{
file
.
labels
=
[
selection
]
}
completion
(
file
,
nil
)
}
}
}
}
}
private
func
moveFileToDocuments
(
fromURL
filepath
:
URL
?)
->
URL
?
{
let
searchPaths
=
NSSearchPathForDirectoriesInDomains
(
.
documentDirectory
,
.
userDomainMask
,
true
)
let
newDirectoryPath
=
searchPaths
.
first
guard
let
directoryPath
=
newDirectoryPath
,
let
url
=
filepath
else
{
return
nil
}
let
destinationURL
=
URL
(
fileURLWithPath
:
"
\(
directoryPath
)
"
+
"/"
+
"
\(
url
.
lastPathComponent
)
"
)
do
{
try
FileManager
.
default
.
moveItem
(
at
:
url
,
to
:
destinationURL
)
}
catch
let
error
{
print
(
error
.
localizedDescription
)
return
nil
}
return
destinationURL
}
class
VLCDragAndDropManager
<
ModelType
>
:
NSObject
{
//, UICollectionViewDragDelegate, UITableViewDragDelegate, UICollectionViewDropDelegate, UITableViewDropDelegate, UIDropInteractionDelegate {
// let utiTypeIdentifiers: [String] = VLCDragAndDropManager.supportedTypeIdentifiers()
// var cateory: ModelType
// /// Returns the supported type identifiers that VLC can process.
// /// It fetches the identifiers in LSItemContentTypes from all the CFBundleDocumentTypes in the info.plist.
// /// Video, Audio and Subtitle formats
// ///
// /// - Returns: Array of UTITypeIdentifiers
// private class func supportedTypeIdentifiers() -> [String] {
// var typeIdentifiers: [String] = []
// if let documents = Bundle.main.infoDictionary?["CFBundleDocumentTypes"] as? [[String: Any]] {
// for item in documents {
// if let value = item["LSItemContentTypes"] as? [String] {
// typeIdentifiers.append(contentsOf: value)
// }
// }
// }
// return typeIdentifiers
// }
//
// @available(*, unavailable, message: "use init(category:)")
// override init() {
// fatalError()
// }
//
// init(cateory: ModelType) {
// self.cateory = cateory
// super.init()
// }
//
// // MARK: - TableView
//
// func tableView(_ tableView: UITableView, canHandle session: UIDropSession) -> Bool {
// return canHandleDropSession(session: session)
// }
//
// func tableView(_ tableView: UITableView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {
// return dragItems(forIndexPath: indexPath)
// }
//
// func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
// return dragItems(forIndexPath: indexPath)
// }
//
// func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
// let operation = dropOperation(hasActiveDrag: tableView.hasActiveDrag, firstSessionItem: session.items.first, withDestinationIndexPath: destinationIndexPath)
// return UITableViewDropProposal(operation: operation, intent: .insertIntoDestinationIndexPath)
// }
//
// func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
// let section = tableView.numberOfSections - 1
// let row = tableView.numberOfRows(inSection: section)
// let destinationPath = coordinator.destinationIndexPath ?? IndexPath(row: row, section: section)
//
// for item in coordinator.items {
// let itemProvider = item.dragItem.itemProvider
// // we're not gonna handle moving of folders
// if let sourceItem = item.dragItem.localObject, fileIsCollection(file: sourceItem as AnyObject) {
// continue
// }
//
// if fileIsFolder(atIndexPath: destinationPath) { // handle dropping onto a folder
// addDragItem(tableView: tableView, dragItem: item, toFolderAt: destinationPath)
// continue
// }
//
// if item.sourceIndexPath != nil { // element within VLC
// moveItem(tableView: tableView, item: item, toIndexPath: destinationPath)
// continue
// }
// // Element dragging from another App
// let placeholder = UITableViewDropPlaceholder(insertionIndexPath: destinationPath, reuseIdentifier: VLCPlaylistTableViewCell.cellIdentifier(), rowHeight: VLCPlaylistTableViewCell.heightOfCell())
// let placeholderContext = coordinator.drop(item.dragItem, to: placeholder)
// createFileWith(itemProvider: itemProvider) {
// [weak self] file, error in
//
// guard let strongSelf = self else { return }
//
// if let file = file {
// placeholderContext.commitInsertion() {
// insertionIndexPath in
// strongSelf.cateory.dragAndDropManagerInsertItem(manager: strongSelf, item: file, atIndexPath: insertionIndexPath)
// }
// }
// if let error = error as? DropError {
// strongSelf.handleError(error: error, itemProvider: item.dragItem.itemProvider)
// placeholderContext.deletePlaceholder()
// }
// }
// }
// }
//
// private func inFolder() -> Bool {
// return cateory.dragAndDropManagerCurrentSelection(manager: self) as? MLLabel != nil
// }
//
// private func moveItem(tableView: UITableView, item: UITableViewDropItem, toIndexPath destinationPath: IndexPath) {
// if let mlFile = item.dragItem.localObject as? MLFile, !mlFile.labels.isEmpty && !inFolder() {
// tableView.performBatchUpdates({
// tableView.insertRows(at: [destinationPath], with: .automatic)
// cateory.dragAndDropManagerInsertItem(manager: self, item: mlFile, atIndexPath: destinationPath)
// cateory.dragAndDropManagerRemoveFileFromFolder(manager: self, file: mlFile)
// }, completion: nil)
// }
// }
//
// private func addDragItem(tableView: UITableView, dragItem item: UITableViewDropItem, toFolderAt index: IndexPath) {
// if let sourcepath = item.sourceIndexPath { // local file that just needs to be moved
// tableView.performBatchUpdates({
// if let file = cateory.dragAndDropManagerRequestsFile(manager: self, atIndexPath: sourcepath) as? MLFile {
// tableView.deleteRows(at: [sourcepath], with: .automatic)
// addFile(file: file, toFolderAt: index)
// cateory.dragAndDropManagerDeleteItem(manager: self, atIndexPath: sourcepath)
// }
// }, completion: nil)
// return
// }