Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Shoo/Shoo.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.6" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.6" />
<PackageReference Include="DynamicData" Version="8.3.27" />
<PackageReference Include="FSharp.Control.Reactive" Version="5.0.5" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="ReactiveElmish.Avalonia" Version="1.0.2" />
<PackageReference Include="ReactiveElmish.Avalonia" Version="1.1.0" />
<PackageReference Include="System.Reactive" Version="6.0.0" />
</ItemGroup>
</Project>
30 changes: 16 additions & 14 deletions src/Shoo/ViewModels/App.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
open System
open System.IO

open DynamicData
open Elmish
open FSharp.Control.Reactive
open ReactiveElmish
open ReactiveElmish.Avalonia

open Shoo.Domain
Expand Down Expand Up @@ -57,7 +55,7 @@ module App =
FileTypes: string
ReplacementsFileName: string
IsActive: bool
FileQueue: SourceCache<File, string>
FileQueue: Map<string, File>
}

type Message =
Expand All @@ -82,7 +80,7 @@ module App =
FileTypes = ""
ReplacementsFileName = ""
IsActive = false
FileQueue = SourceCache.create _.FullName
FileQueue = Map.empty
}
|> withoutCommand

Expand All @@ -105,29 +103,33 @@ module App =
| QueueFileCopy path ->
let file = mkFile path model.DestinationDirectory.Path
{ model with
FileQueue = model.FileQueue |> SourceCache.addOrUpdate file
FileQueue = model.FileQueue.Add(file.FullName, file)
} |> withoutCommand
| UpdateFileStatus (fileName, progress, moveFileStatus) ->
let file = model.FileQueue.Lookup fileName
let file = model.FileQueue[fileName]

let updatedFile = { file.Value with Progress = progress; Status = moveFileStatus }
let updatedFile = { file with Progress = progress; Status = moveFileStatus }
{ model with
FileQueue = model.FileQueue |> SourceCache.addOrUpdate updatedFile
FileQueue = model.FileQueue.Add(updatedFile.FullName, updatedFile)
} |> withoutCommand
| RemoveFile fileFullName ->
{ model with
FileQueue = model.FileQueue |> SourceCache.removeKey fileFullName
FileQueue = model.FileQueue.Remove fileFullName
} |> withoutCommand
| ClearCompleted ->
let completedFiles =
model.FileQueue.Items
model.FileQueue
|> Map.toSeq
|> Seq.map snd
|> Seq.filter (fun file -> file.Status = Complete)
|> Seq.map _.FullName
|> Seq.toList

// Remove completed files from the queue
let fileQueue: Map<string, File> =
completedFiles
|> Seq.fold (fun queue file -> queue.Remove file) model.FileQueue

model.FileQueue.RemoveKeys completedFiles

model |> withoutCommand
{ model with FileQueue = fileQueue } |> withoutCommand

| Terminate -> model |> withoutCommand

Expand Down
53 changes: 24 additions & 29 deletions src/Shoo/ViewModels/MainWindowViewModel.fs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
namespace Shoo.ViewModels

open System
open System.Collections.Generic

open DynamicData
open ReactiveElmish
open ReactiveUI

Expand Down Expand Up @@ -38,30 +36,10 @@ type FileViewModel(file: File) =
type MainWindowViewModel(folderPicker: Services.FolderPickerService) as this =
inherit ReactiveElmishViewModel()

let mutable fileQueue = Unchecked.defaultof<_>
let progress = Progress(UpdateFileStatus >> store.Dispatch)

let createFileViewModel (file: Shoo.Domain.File) = new FileViewModel(file)

do
let progress = Progress(UpdateFileStatus >> store.Dispatch)

let copyEngine = CopyFileEngine.create progress
this.AddDisposable copyEngine

store.Model.FileQueue.Connect()
.TransformWithInlineUpdate(
(fun file ->
file |> mkCopyOperation |> copyEngine.Queue

new FileViewModel(file)),
(fun viewModel file ->
viewModel.Progress <- file.Progress
viewModel.Status <- file.Status))
.Sort(Comparer.Create(fun (x: FileViewModel) y -> DateTime.Compare(x.Time, y.Time)))
.Bind(&fileQueue)
.DisposeMany()
.Subscribe()
|> this.AddDisposable
let copyEngine = CopyFileEngine.create progress
do this.AddDisposable copyEngine

member this.SourceDirectory
with get () = this.Bind(store, _.SourceDirectory.Path)
Expand Down Expand Up @@ -95,10 +73,26 @@ type MainWindowViewModel(folderPicker: Services.FolderPickerService) as this =
this.Bind(
store,
fun model ->
model.FileQueue.Items
model.FileQueue
|> Map.toSeq
|> Seq.map snd
|> Seq.exists (fun file -> file.Status = Complete))

member this.FileQueue = fileQueue
member this.FileQueue =
this.BindKeyedList(
store
, _.FileQueue
, map =
fun file ->
file |> mkCopyOperation |> copyEngine.Queue
new FileViewModel(file)
, getKey = _.FullName
, update =
fun file viewModel ->
viewModel.Progress <- file.Progress
viewModel.Status <- file.Status
, sortBy = _.Time
)

member this.SelectSourceDirectory() =
task {
Expand All @@ -112,7 +106,8 @@ type MainWindowViewModel(folderPicker: Services.FolderPickerService) as this =
return store.Dispatch(UpdateDestinationDirectory path)
}

member this.ClearCompletedFiles () = store.Dispatch ClearCompleted
member this.ClearCompletedFiles () =
store.Dispatch ClearCompleted

static member DesignVM =
static member DesignVM =
new MainWindowViewModel(Design.stub)