Add project files.

master
Amir Hossein Khademi 2021-01-15 18:13:54 +03:30
commit c91bde761e
72 changed files with 5186 additions and 0 deletions

63
.gitattributes vendored 100644
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

340
.gitignore vendored 100644
View File

@ -0,0 +1,340 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb

25
Plix.sln 100644
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlixP", "PlixP\PlixP.csproj", "{D97DA4A8-8F8C-4A43-A868-69912C04BEE7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D97DA4A8-8F8C-4A43-A868-69912C04BEE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D97DA4A8-8F8C-4A43-A868-69912C04BEE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D97DA4A8-8F8C-4A43-A868-69912C04BEE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D97DA4A8-8F8C-4A43-A868-69912C04BEE7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {17816672-B5D2-4079-83EA-D88ABDD69DEE}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=Plix_002ECore_002EAnnotations/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

BIN
PlixLogo.ico 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
PlixLogo.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

44
PlixP/App.xaml 100644
View File

@ -0,0 +1,44 @@
<prism:PrismApplication
x:Class="PlixP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:PlixP"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:materialDesignDemo="clr-namespace:PlixP"
xmlns:prism="http://prismlibrary.com/"
xmlns:showMeTheXaml="clr-namespace:ShowMeTheXAML;assembly=ShowMeTheXAML"
xmlns:smtxAe="clr-namespace:ShowMeTheXAML;assembly=ShowMeTheXAML"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<hc:Theme Name="HandyTheme" Skin="Dark" />
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Key="DictionaryTest">
<system:String x:Key="str1a">String 1A</system:String>
<system:String x:Key="str1b">String 1B</system:String>
<system:String x:Key="str1c">String 1C</system:String>
<system:String x:Key="str1d">String 1A</system:String>
<system:String x:Key="str1e">String 1B</system:String>
<system:String x:Key="str1f">String 1C</system:String>
</ResourceDictionary>
<ResourceDictionary x:Key="Material">
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme
BaseTheme="Dark"
PrimaryColor="Yellow"
SecondaryColor="Orange" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<SolidColorBrush x:Key="PrimaryBrush" Color="#f1c40f" />
</ResourceDictionary>
</Application.Resources>
</prism:PrismApplication>

55
PlixP/App.xaml.cs 100644
View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Prism.Ioc;
using PlixP.Views;
using System.Windows;
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using PlixP.Extentions;
using PlixP.Models;
using PlixP.Repositories;
using PlixP.Repositories.Contracts;
using PlixP.Services;
using PlixP.Services.Contracts;
namespace PlixP
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
protected override Window CreateShell()
{
var _catcherService = new CatcherService();
_catcherService.Delete<List<Movie>>(CatcherKeys.MovieList);
using (var _context = new PlixContext())
{
_context.Database.Migrate();
if (_context.Categories.Count() == 0)
{
_context.Categories.Add(new Category
{
Name = "Uncategorized"
});
_context.SaveChanges();
}
}
AutoMapperConfig.ConfigurationMapper();
App.Current.ConfigureExceptionHandling(AppDomain.CurrentDomain);
MovieServiceRealTime.Instance.StartReal();
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<MovieList>();
containerRegistry.Register<IServiceWrapper,ServiceWrapper>();
containerRegistry.Register<IRepositoryWrapper, RepositoryWrapper>();
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Extentions
{
public static class Assert
{
public static void NotNull<T>(T obj, string name, string message = null)
where T : class
{
if (obj is null)
throw new ArgumentNullException($"{name} : {typeof(T)}", message);
}
public static void NotNull<T>(T? obj, string name, string message = null)
where T : struct
{
if (!obj.HasValue)
throw new ArgumentNullException($"{name} : {typeof(T)}", message);
}
public static void NotEmpty<T>(T obj, string name, string message = null, T defaultValue = null)
where T : class
{
if (obj == defaultValue
|| (obj is string str && string.IsNullOrWhiteSpace(str))
|| (obj is IEnumerable list && !list.Cast<object>().Any()))
{
throw new ArgumentException("Argument is empty : " + message, $"{name} : {typeof(T)}");
}
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using PlixP.Models;
namespace PlixP.Extentions
{
public static class AutoMapperConfig
{
public static void ConfigurationMapper()
{
Mapper.Initialize(config => { config.AddCustomMapping(Assembly.GetEntryAssembly()); });
Mapper.Configuration.CompileMappings();
}
public static void AddCustomMapping(this IMapperConfigurationExpression expression, Assembly assemblies)
{
var allTypes = assemblies.ExportedTypes;
var list = allTypes
.Where(type => type.IsClass && !type.IsAbstract && type.GetInterfaces().Contains(typeof(IMapperConf)))
.Select(type => (IMapperConf)Activator.CreateInstance(type)).ToList();
expression.AddProfile(new CustomMappingProfile(list));
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using MessageBox = HandyControl.Controls.MessageBox;
namespace PlixP.Extentions
{
public static class WpfExtensions
{
public static Brush FromHex(string hexColor)
{
return (SolidColorBrush)(new BrushConverter().ConvertFrom(hexColor));
}
public static void ConfigureExceptionHandling(this Application application, AppDomain appDomain)
{
application.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
application.DispatcherUnhandledException += Application_DispatcherUnhandledException;
appDomain.UnhandledException += AppDomain_UnhandledException;
}
private static void AppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show(e.ExceptionObject.ToString());
}
private static void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (e.Handled == false)
{
MessageBox.Show(e.Exception.Message);
e.Handled = true;
}
}
private static void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (e.Handled == false)
{
MessageBox.Show(e.Exception.Message);
e.Handled = true;
}
}
}
}

View File

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="PropertyChanged" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="InjectOnPropertyNameChanged" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the On_PropertyName_Changed feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="TriggerDependentProperties" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the Dependent properties feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="EnableIsChangedProperty" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the IsChanged property feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="EventInvokerNames" type="xs:string">
<xs:annotation>
<xs:documentation>Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="CheckForEquality" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="CheckForEqualityUsingBaseEquals" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should use the Equals method resolved from the base class.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseStaticEqualsFromBase" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should use the static Equals method resolved from the base class.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="SuppressWarnings" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to turn off build warnings from this weaver.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="SuppressOnPropertyNameChangedWarning" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to turn off build warnings about mismatched On_PropertyName_Changed methods.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -0,0 +1,244 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PlixP.Models;
namespace PlixP.Migrations
{
[DbContext(typeof(PlixContext))]
[Migration("20201219204740_init")]
partial class init
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.1");
modelBuilder.Entity("PlixP.Models.Category", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<bool>("IsRemoved")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Categories");
});
modelBuilder.Entity("PlixP.Models.CategoryMovie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CategoryId")
.HasColumnType("INTEGER");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<bool>("IsRemoved")
.HasColumnType("INTEGER");
b.Property<int>("MovieId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("MovieId");
b.ToTable("CategoryMovies");
});
modelBuilder.Entity("PlixP.Models.Movie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Actors")
.HasColumnType("TEXT");
b.Property<string>("Awards")
.HasColumnType("TEXT");
b.Property<string>("BoxOffice")
.HasColumnType("TEXT");
b.Property<string>("Country")
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<string>("DVD")
.HasColumnType("TEXT");
b.Property<string>("Director")
.HasColumnType("TEXT");
b.Property<string>("FileName")
.HasColumnType("TEXT");
b.Property<string>("Genre")
.HasColumnType("TEXT");
b.Property<bool>("IsRemoved")
.HasColumnType("INTEGER");
b.Property<bool>("IsSeen")
.HasColumnType("INTEGER");
b.Property<string>("Language")
.HasColumnType("TEXT");
b.Property<string>("Location")
.HasColumnType("TEXT");
b.Property<string>("Metascore")
.HasColumnType("TEXT");
b.Property<string>("Plot")
.HasColumnType("TEXT");
b.Property<string>("Poster")
.HasColumnType("TEXT");
b.Property<string>("Production")
.HasColumnType("TEXT");
b.Property<string>("Quality")
.HasColumnType("TEXT");
b.Property<string>("Rated")
.HasColumnType("TEXT");
b.Property<string>("Released")
.HasColumnType("TEXT");
b.Property<string>("Response")
.HasColumnType("TEXT");
b.Property<string>("Runtime")
.HasColumnType("TEXT");
b.Property<int>("SyncStatus")
.HasColumnType("INTEGER");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<string>("Type")
.HasColumnType("TEXT");
b.Property<string>("Website")
.HasColumnType("TEXT");
b.Property<string>("Writer")
.HasColumnType("TEXT");
b.Property<string>("Year")
.HasColumnType("TEXT");
b.Property<string>("imdbID")
.HasColumnType("TEXT");
b.Property<string>("imdbRating")
.HasColumnType("TEXT");
b.Property<string>("imdbVotes")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Movies");
});
modelBuilder.Entity("PlixP.Models.Rating", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<bool>("IsRemoved")
.HasColumnType("INTEGER");
b.Property<int>("MovieId")
.HasColumnType("INTEGER");
b.Property<string>("Source")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("MovieId");
b.ToTable("Ratings");
});
modelBuilder.Entity("PlixP.Models.CategoryMovie", b =>
{
b.HasOne("PlixP.Models.Category", "Category")
.WithMany("Movies")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("PlixP.Models.Movie", "Movie")
.WithMany("Category")
.HasForeignKey("MovieId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("Movie");
});
modelBuilder.Entity("PlixP.Models.Rating", b =>
{
b.HasOne("PlixP.Models.Movie", "Movie")
.WithMany("Ratings")
.HasForeignKey("MovieId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Movie");
});
modelBuilder.Entity("PlixP.Models.Category", b =>
{
b.Navigation("Movies");
});
modelBuilder.Entity("PlixP.Models.Movie", b =>
{
b.Navigation("Category");
b.Navigation("Ratings");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,150 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace PlixP.Migrations
{
public partial class init : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Categories",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Name = table.Column<string>(type: "TEXT", nullable: true),
IsRemoved = table.Column<bool>(type: "INTEGER", nullable: false),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Categories", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Movies",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
FileName = table.Column<string>(type: "TEXT", nullable: true),
Location = table.Column<string>(type: "TEXT", nullable: true),
Quality = table.Column<string>(type: "TEXT", nullable: true),
Title = table.Column<string>(type: "TEXT", nullable: true),
Year = table.Column<string>(type: "TEXT", nullable: true),
Rated = table.Column<string>(type: "TEXT", nullable: true),
Released = table.Column<string>(type: "TEXT", nullable: true),
Runtime = table.Column<string>(type: "TEXT", nullable: true),
Genre = table.Column<string>(type: "TEXT", nullable: true),
Director = table.Column<string>(type: "TEXT", nullable: true),
Writer = table.Column<string>(type: "TEXT", nullable: true),
Actors = table.Column<string>(type: "TEXT", nullable: true),
Plot = table.Column<string>(type: "TEXT", nullable: true),
Language = table.Column<string>(type: "TEXT", nullable: true),
Country = table.Column<string>(type: "TEXT", nullable: true),
Awards = table.Column<string>(type: "TEXT", nullable: true),
Poster = table.Column<string>(type: "TEXT", nullable: true),
Metascore = table.Column<string>(type: "TEXT", nullable: true),
imdbRating = table.Column<string>(type: "TEXT", nullable: true),
imdbVotes = table.Column<string>(type: "TEXT", nullable: true),
imdbID = table.Column<string>(type: "TEXT", nullable: true),
Type = table.Column<string>(type: "TEXT", nullable: true),
DVD = table.Column<string>(type: "TEXT", nullable: true),
BoxOffice = table.Column<string>(type: "TEXT", nullable: true),
Production = table.Column<string>(type: "TEXT", nullable: true),
Website = table.Column<string>(type: "TEXT", nullable: true),
Response = table.Column<string>(type: "TEXT", nullable: true),
IsSeen = table.Column<bool>(type: "INTEGER", nullable: false),
SyncStatus = table.Column<int>(type: "INTEGER", nullable: false),
IsRemoved = table.Column<bool>(type: "INTEGER", nullable: false),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Movies", x => x.Id);
});
migrationBuilder.CreateTable(
name: "CategoryMovies",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
CategoryId = table.Column<int>(type: "INTEGER", nullable: false),
MovieId = table.Column<int>(type: "INTEGER", nullable: false),
IsRemoved = table.Column<bool>(type: "INTEGER", nullable: false),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CategoryMovies", x => x.Id);
table.ForeignKey(
name: "FK_CategoryMovies_Categories_CategoryId",
column: x => x.CategoryId,
principalTable: "Categories",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CategoryMovies_Movies_MovieId",
column: x => x.MovieId,
principalTable: "Movies",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Ratings",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Source = table.Column<string>(type: "TEXT", nullable: true),
Value = table.Column<string>(type: "TEXT", nullable: true),
MovieId = table.Column<int>(type: "INTEGER", nullable: false),
IsRemoved = table.Column<bool>(type: "INTEGER", nullable: false),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Ratings", x => x.Id);
table.ForeignKey(
name: "FK_Ratings_Movies_MovieId",
column: x => x.MovieId,
principalTable: "Movies",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_CategoryMovies_CategoryId",
table: "CategoryMovies",
column: "CategoryId");
migrationBuilder.CreateIndex(
name: "IX_CategoryMovies_MovieId",
table: "CategoryMovies",
column: "MovieId");
migrationBuilder.CreateIndex(
name: "IX_Ratings_MovieId",
table: "Ratings",
column: "MovieId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CategoryMovies");
migrationBuilder.DropTable(
name: "Ratings");
migrationBuilder.DropTable(
name: "Categories");
migrationBuilder.DropTable(
name: "Movies");
}
}
}

View File

@ -0,0 +1,242 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PlixP.Models;
namespace PlixP.Migrations
{
[DbContext(typeof(PlixContext))]
partial class PlixContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.1");
modelBuilder.Entity("PlixP.Models.Category", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<bool>("IsRemoved")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Categories");
});
modelBuilder.Entity("PlixP.Models.CategoryMovie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CategoryId")
.HasColumnType("INTEGER");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<bool>("IsRemoved")
.HasColumnType("INTEGER");
b.Property<int>("MovieId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("MovieId");
b.ToTable("CategoryMovies");
});
modelBuilder.Entity("PlixP.Models.Movie", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Actors")
.HasColumnType("TEXT");
b.Property<string>("Awards")
.HasColumnType("TEXT");
b.Property<string>("BoxOffice")
.HasColumnType("TEXT");
b.Property<string>("Country")
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<string>("DVD")
.HasColumnType("TEXT");
b.Property<string>("Director")
.HasColumnType("TEXT");
b.Property<string>("FileName")
.HasColumnType("TEXT");
b.Property<string>("Genre")
.HasColumnType("TEXT");
b.Property<bool>("IsRemoved")
.HasColumnType("INTEGER");
b.Property<bool>("IsSeen")
.HasColumnType("INTEGER");
b.Property<string>("Language")
.HasColumnType("TEXT");
b.Property<string>("Location")
.HasColumnType("TEXT");
b.Property<string>("Metascore")
.HasColumnType("TEXT");
b.Property<string>("Plot")
.HasColumnType("TEXT");
b.Property<string>("Poster")
.HasColumnType("TEXT");
b.Property<string>("Production")
.HasColumnType("TEXT");
b.Property<string>("Quality")
.HasColumnType("TEXT");
b.Property<string>("Rated")
.HasColumnType("TEXT");
b.Property<string>("Released")
.HasColumnType("TEXT");
b.Property<string>("Response")
.HasColumnType("TEXT");
b.Property<string>("Runtime")
.HasColumnType("TEXT");
b.Property<int>("SyncStatus")
.HasColumnType("INTEGER");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<string>("Type")
.HasColumnType("TEXT");
b.Property<string>("Website")
.HasColumnType("TEXT");
b.Property<string>("Writer")
.HasColumnType("TEXT");
b.Property<string>("Year")
.HasColumnType("TEXT");
b.Property<string>("imdbID")
.HasColumnType("TEXT");
b.Property<string>("imdbRating")
.HasColumnType("TEXT");
b.Property<string>("imdbVotes")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Movies");
});
modelBuilder.Entity("PlixP.Models.Rating", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<bool>("IsRemoved")
.HasColumnType("INTEGER");
b.Property<int>("MovieId")
.HasColumnType("INTEGER");
b.Property<string>("Source")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("MovieId");
b.ToTable("Ratings");
});
modelBuilder.Entity("PlixP.Models.CategoryMovie", b =>
{
b.HasOne("PlixP.Models.Category", "Category")
.WithMany("Movies")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("PlixP.Models.Movie", "Movie")
.WithMany("Category")
.HasForeignKey("MovieId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("Movie");
});
modelBuilder.Entity("PlixP.Models.Rating", b =>
{
b.HasOne("PlixP.Models.Movie", "Movie")
.WithMany("Ratings")
.HasForeignKey("MovieId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Movie");
});
modelBuilder.Entity("PlixP.Models.Category", b =>
{
b.Navigation("Movies");
});
modelBuilder.Entity("PlixP.Models.Movie", b =>
{
b.Navigation("Category");
b.Navigation("Ratings");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
namespace PlixP.Models
{
/// <summary>
/// Base Dto Class initial map config between entity and dto
/// </summary>
/// <typeparam name="TDto">Type of Dto Class</typeparam>
/// <typeparam name="TEntity">Type of Entity Class</typeparam>
public abstract class BaseDto<TDto, TEntity> : IMapperConf
where TDto : class, new()
where TEntity : new()
{
public TEntity ToEntity()
{
return Mapper.Map<TEntity>(CastToDerivedClass(this));
}
public TEntity ToEntity(TEntity entity)
{
return Mapper.Map(CastToDerivedClass(this), entity);
}
public static TDto FromEntity(TEntity model)
{
return Mapper.Map<TDto>(model);
}
protected TDto CastToDerivedClass(BaseDto<TDto, TEntity> baseInstance)
{
return Mapper.Map<TDto>(baseInstance);
}
public virtual void MapperConfig(Profile profile)
{
var mappingExpression = profile.CreateMap<TDto, TEntity>();
var dtoType = typeof(TDto);
var entityType = typeof(TEntity);
//Ignore any property of source (like Post.Author) that dose not contains in destination
foreach (var property in entityType.GetProperties())
{
if (dtoType.GetProperty(property.Name) == null)
mappingExpression.ForMember(property.Name, opt => opt.Ignore());
}
CustomMappings(mappingExpression.ReverseMap());
}
public virtual void CustomMappings(IMappingExpression<TEntity, TDto> mapping)
{
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Models
{
[Serializable]
public class Category : Entity
{
public string Name { get; set; }
public virtual ICollection<CategoryMovie> Movies { get; set; }
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Models
{
[Serializable]
public class CategoryMovie : Entity
{
public int CategoryId { get; set; }
public int MovieId { get; set; }
public Category Category { get; set; }
public Movie Movie { get; set; }
[NotMapped]
public bool IsEditable { get; set; } = false;
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
namespace PlixP.Models
{
public class CustomMappingProfile : Profile
{
public CustomMappingProfile(IEnumerable<IMapperConf> mapperConfs)
{
foreach (var mapperConf in mapperConfs)
mapperConf.MapperConfig(this);
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Models
{
[Serializable]
public class Entity
{
[Key]
public int Id { get; set; }
public bool IsRemoved { get; set; }
public DateTime CreationDate { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
namespace PlixP.Models
{
public interface IMapperConf
{
void MapperConfig(Profile profile);
}
}

View File

@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Models
{
public enum SyncStatus
{
Synced,
NotSynced
}
[Serializable]
public class Movie : Entity, ICloneable
{
public string FullName
{
get
{
if (Location != null && FileName != null)
return Path.Combine(Location, FileName);
else
return null;
}
}
public string FileName { get; set; }
public string Location { get; set; }
public string Quality { get; set; }
public string Title { get; set; }
public string Year { get; set; }
public int IntYear
{
get
{
int year;
if (string.IsNullOrEmpty(Year))
return 0;
if (int.TryParse(Year, out year))
return year;
else
return 0;
}
}
public string Rated { get; set; }
public string Released { get; set; }
public string Runtime { get; set; }
public string Genre { get; set; }
public string Director { get; set; }
public string Writer { get; set; }
public string Actors { get; set; }
public string Plot { get; set; }
public string Language { get; set; }
public string Country { get; set; }
public string Awards { get; set; }
public string Poster { get; set; }
public string Metascore { get; set; }
public string imdbRating { get; set; }
public string imdbVotes { get; set; }
public string imdbID { get; set; }
public string Type { get; set; }
public string DVD { get; set; }
public string BoxOffice { get; set; }
public string Production { get; set; }
public string Website { get; set; }
public string Response { get; set; }
[NotMapped]
public bool IsDubbed
{
get
{
if (FullName != null && FullName.ToLower().Contains("dubbed"))
return true;
else
return false;
}
}
public bool IsSeen { get; set; }
[NotMapped]
public Color SeenStatusColor
{
get
{
if (IsSeen)
return Color.LimeGreen;
else
return Color.OrangeRed;
}
}
public SyncStatus SyncStatus { get; set; }
public List<Rating> Ratings { get; set; }
public ObservableCollection<CategoryMovie> Category { get; set; }
[NotMapped]
public List<string> CategoryNames { get; set; }
public object Clone()
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Context = new StreamingContext(StreamingContextStates.Clone);
formatter.Serialize(ms, this);
ms.Position = 0;
return formatter.Deserialize(ms);
}
}
}
}

View File

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
namespace PlixP.Models
{
public class MovieDto : BaseDto<MovieDto,Movie>
{
public int Id { get; set; }
public bool IsRemoved { get; set; }
public DateTime CreationDate { get; set; }
public string FullName
{
get;
set;
}
public string FileName { get; set; }
public string Location { get; set; }
public string Quality { get; set; }
public string Title { get; set; }
public string Year { get; set; }
public string Rated { get; set; }
public string Released { get; set; }
public string Runtime { get; set; }
public string Genre { get; set; }
public string Director { get; set; }
public string Writer { get; set; }
public string Actors { get; set; }
public string Plot { get; set; }
public string Language { get; set; }
public string Country { get; set; }
public string Awards { get; set; }
public string Poster { get; set; }
public string Metascore { get; set; }
public string imdbRating { get; set; }
public string imdbVotes { get; set; }
public string imdbID { get; set; }
public string Type { get; set; }
public string DVD { get; set; }
public string BoxOffice { get; set; }
public string Production { get; set; }
public string Website { get; set; }
public string Response { get; set; }
public bool IsDubbed
{
get;
set;
}
public bool IsSeen { get; set; }
public Color SeenStatusColor
{
get;
set;
}
public SyncStatus SyncStatus { get; set; }
public List<Rating> Ratings { get; set; }
public ObservableCollection<CategoryMovie> Category { get; set; }
public List<string> CategoryNames { get; set; }
public override void CustomMappings(IMappingExpression<Movie, MovieDto> mapping)
{
base.CustomMappings(mapping);
mapping.ForMember(m => m.CategoryNames
, org => org.MapFrom(m => m.Category.Select(c => c.Category.Name).ToList()));
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Models
{
public class MovieListModel : INotifyPropertyChanged
{
public ObservableCollection<Movie> OriginalMovies { get; set; } = new ObservableCollection<Movie>();
public ObservableCollection<Category> OriginalCategories { get; set; } = new ObservableCollection<Category>();
public Dictionary<string, int> OriginalGenres { get; set; } = new Dictionary<string, int>();
public List<string> Genres
{
get
{
return OriginalGenres.Select(g => string.Format("{0} | {1}", g.Key, g.Value.ToString())).ToList();
}
}
public ObservableCollection<Movie> UnPagedMovies { get; set; } = new ObservableCollection<Movie>();
public ObservableCollection<Movie> PageMovies { get; set; } = new ObservableCollection<Movie>();
public int MoviesCount { get; set; }
public bool AllChecked { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Models
{
public class PlixContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite("Data Source=plix.db");
public DbSet<Movie> Movies { get; set; }
public DbSet<Rating> Ratings { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<CategoryMovie> CategoryMovies { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Models
{
[Serializable]
public class Rating : Entity
{
public string Source { get; set; }
public string Value { get; set; }
public int MovieId { get; set; }
public Movie Movie { get; set; }
}
}

BIN
PlixP/PlixLogo.ico 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

46
PlixP/PlixP.csproj 100644
View File

@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<AssemblyName>PlixP</AssemblyName>
<ApplicationIcon>PlixLogo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\PlixLogo.ico" />
<None Remove="Resources\SPLASH.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="8.0.0" />
<PackageReference Include="Fody" Version="6.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="HandyControls" Version="3.0.0-rc.1" />
<PackageReference Include="MaterialDesignColors" Version="2.0.0-ci2312" />
<PackageReference Include="MaterialDesignThemes" Version="4.0.0-ci2312" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Prism.Unity" Version="8.0.0.1909" />
<PackageReference Include="Prism.Wpf" Version="8.0.0.1909" />
<PackageReference Include="PropertyChanged.Fody" Version="3.3.1" />
<PackageReference Include="RestSharp" Version="106.11.7" />
<PackageReference Include="ShowMeTheXAML" Version="2.0.0" />
<PackageReference Include="Xam.Plugins.Settings" Version="4.1.0-beta" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\PlixLogo.ico" />
</ItemGroup>
<ItemGroup>
<SplashScreen Include="Resources\SPLASH.png" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace PlixP.Renders
{
public class ImageCacher : Image
{
private string BaseRepos = string.Format("{0}\\PlixMovieCacheFolder\\", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
private List<FileInfo> FileInfos;
private bool Sourced = false;
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register(nameof(ImageSource), typeof(string), typeof(ImageCacher),
new PropertyMetadata("", new PropertyChangedCallback(OnSetTextChanged)));
private static void OnSetTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var imageC = d as ImageCacher;
var source = e.NewValue as string;
if (source != null)
{
var name = source.ToString().Split('/').Last();
var image = imageC.FileInfos.FirstOrDefault(f => f.Name == name);
if (image != null)
{
imageC.Sourced = true;
var src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri(Path.Combine(image.DirectoryName, image.Name), UriKind.Absolute);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
imageC.Source = src;
}
else
{
try
{
App.Current.Dispatcher.Invoke(() =>
{
using (WebClient webClient = new WebClient())
{
if (source != "N/A")
{
byte[] data = webClient.DownloadData(source.ToString());
File.WriteAllBytes(Path.Combine(imageC.BaseRepos, name), data);
imageC.Source = new BitmapImage(new Uri(Path.Combine(imageC.BaseRepos, name)));
imageC.Sourced = true;
}
}
});
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
}
}
}
public string ImageSource
{
get { return (string)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public ImageCacher()
{
var directoryInfo = new DirectoryInfo(BaseRepos);
if (!Directory.Exists(BaseRepos))
{
Directory.CreateDirectory(BaseRepos);
}
FileInfos = directoryInfo.GetFiles().ToList();
if (FileInfos == null)
FileInfos = new List<FileInfo>();
}
}
}

View File

@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PlixP.Extentions;
using PlixP.Models;
using PlixP.Repositories.Contracts;
namespace PlixP.Repositories
{
public class BaseRepository<T> : IBaseRepository<T>
where T : Entity
{
protected readonly PlixContext DbContext;
public DbSet<T> Entities { get; }
public virtual IQueryable<T> Table => Entities.Where(e => e.IsRemoved == false);
public virtual IQueryable<T> TableNoTracking => Entities.AsNoTracking().Where(e => e.IsRemoved == false);
public BaseRepository(PlixContext dbContext)
{
DbContext = dbContext;
Entities = DbContext.Set<T>(); // City => Cities
}
#region Async Method
public virtual async Task<T> GetByIdAsync(CancellationToken cancellationToken, params object[] ids)
{
var entity = await Entities.FindAsync(ids, cancellationToken);
DbContext.Entry(entity).State = EntityState.Detached;
return entity;
}
public virtual async Task AddAsync(T entity, CancellationToken cancellationToken, bool saveNow = true)
{
Assert.NotNull(entity, nameof(entity));
entity.CreationDate = DateTime.Now;
await Entities.AddAsync(entity, cancellationToken).ConfigureAwait(false);
if (saveNow)
await DbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
public virtual async Task AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true)
{
Assert.NotNull(entities, nameof(entities));
await Entities.AddRangeAsync(entities, cancellationToken).ConfigureAwait(false);
if (saveNow)
await DbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
public virtual async Task UpdateAsync(T entity, CancellationToken cancellationToken, bool saveNow = true)
{
Assert.NotNull(entity, nameof(entity));
DbContext.Entry(entity).State = EntityState.Detached;
await DbContext.SaveChangesAsync(cancellationToken);
//DbContext.Entry(entity).State = EntityState.Modified;
DbContext.Update(entity);
//DbContext.Entry(entity).CurrentValues.SetValues(entity);
if (saveNow)
await DbContext.SaveChangesAsync(cancellationToken);
}
public virtual async Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true)
{
Assert.NotNull(entities, nameof(entities));
Entities.UpdateRange(entities);
if (saveNow)
await DbContext.SaveChangesAsync(cancellationToken);
}
public virtual async Task DeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true)
{
Assert.NotNull(entity, nameof(entity));
entity.IsRemoved = true;
Entities.Update(entity);
if (saveNow)
await DbContext.SaveChangesAsync(cancellationToken);
}
public async Task HardDeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true)
{
Assert.NotNull(entity, nameof(entity));
Entities.Remove(entity);
if (saveNow)
await DbContext.SaveChangesAsync(cancellationToken);
}
public virtual async Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true)
{
Assert.NotNull(entities, nameof(entities));
foreach (var apiEntity in entities)
{
apiEntity.IsRemoved = true;
Entities.Update(apiEntity);
}
if (saveNow)
await DbContext.SaveChangesAsync(cancellationToken);
}
#endregion
#region Sync Methods
public virtual T GetById(params object[] ids)
{
var ent = Entities.Find(ids);
Detach(ent);
return ent;
}
public virtual void Add(T entity, bool saveNow = true)
{
Assert.NotNull(entity, nameof(entity));
Entities.Add(entity);
if (saveNow)
DbContext.SaveChanges();
}
public virtual void AddRange(IEnumerable<T> entities, bool saveNow = true)
{
Assert.NotNull(entities, nameof(entities));
Entities.AddRange(entities);
if (saveNow)
DbContext.SaveChanges();
}
public virtual void Update(T entity, bool saveNow = true)
{
Assert.NotNull(entity, nameof(entity));
Detach(entity);
Entities.Update(entity);
DbContext.SaveChanges();
}
public virtual void UpdateRange(IEnumerable<T> entities, bool saveNow = true)
{
Assert.NotNull(entities, nameof(entities));
Entities.UpdateRange(entities);
if (saveNow)
DbContext.SaveChanges();
}
public virtual void Delete(T entity, bool saveNow = true)
{
Assert.NotNull(entity, nameof(entity));
Entities.Remove(entity);
if (saveNow)
DbContext.SaveChanges();
}
public virtual void DeleteRange(IEnumerable<T> entities, bool saveNow = true)
{
Assert.NotNull(entities, nameof(entities));
Entities.RemoveRange(entities);
if (saveNow)
DbContext.SaveChanges();
}
#endregion
#region Attach & Detach
public virtual void Detach(T entity)
{
Assert.NotNull(entity, nameof(entity));
var entry = DbContext.Entry(entity);
if (entry != null)
entry.State = EntityState.Detached;
}
public virtual void Attach(T entity)
{
Assert.NotNull(entity, nameof(entity));
if (DbContext.Entry(entity).State == EntityState.Detached)
Entities.Attach(entity);
}
#endregion
#region Explicit Loading
public virtual async Task LoadCollectionAsync<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> collectionProperty, CancellationToken cancellationToken)
where TProperty : class
{
Attach(entity);
var collection = DbContext.Entry(entity).Collection(collectionProperty);
if (!collection.IsLoaded)
await collection.LoadAsync(cancellationToken).ConfigureAwait(false);
}
public virtual void LoadCollection<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> collectionProperty)
where TProperty : class
{
Attach(entity);
var collection = DbContext.Entry(entity).Collection(collectionProperty);
if (!collection.IsLoaded)
collection.Load();
}
public virtual async Task LoadReferenceAsync<TProperty>(T entity, Expression<Func<T, TProperty>> referenceProperty, CancellationToken cancellationToken)
where TProperty : class
{
Attach(entity);
var reference = DbContext.Entry(entity).Reference(referenceProperty);
if (!reference.IsLoaded)
await reference.LoadAsync(cancellationToken).ConfigureAwait(false);
}
public virtual void LoadReference<TProperty>(T entity, Expression<Func<T, TProperty>> referenceProperty)
where TProperty : class
{
Attach(entity);
var reference = DbContext.Entry(entity).Reference(referenceProperty);
if (!reference.IsLoaded)
reference.Load();
}
#endregion
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PlixP.Models;
namespace PlixP.Repositories.Contracts
{
public interface IBaseRepository<T> where T : Entity
{
DbSet<T> Entities { get; }
IQueryable<T> Table { get; }
IQueryable<T> TableNoTracking { get; }
void Add(T entity, bool saveNow = true);
Task AddAsync(T entity, CancellationToken cancellationToken, bool saveNow = true);
void AddRange(IEnumerable<T> entities, bool saveNow = true);
Task AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true);
void Attach(T entity);
void Delete(T entity, bool saveNow = true);
Task DeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true);
Task HardDeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true);
void DeleteRange(IEnumerable<T> entities, bool saveNow = true);
Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true);
void Detach(T entity);
T GetById(params object[] ids);
Task<T> GetByIdAsync(CancellationToken cancellationToken, params object[] ids);
void LoadCollection<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> collectionProperty) where TProperty : class;
Task LoadCollectionAsync<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> collectionProperty, CancellationToken cancellationToken) where TProperty : class;
void LoadReference<TProperty>(T entity, Expression<Func<T, TProperty>> referenceProperty) where TProperty : class;
Task LoadReferenceAsync<TProperty>(T entity, Expression<Func<T, TProperty>> referenceProperty, CancellationToken cancellationToken) where TProperty : class;
void Update(T entity, bool saveNow = true);
Task UpdateAsync(T entity, CancellationToken cancellationToken, bool saveNow = true);
void UpdateRange(IEnumerable<T> entities, bool saveNow = true);
Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken, bool saveNow = true);
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PlixP.Models;
namespace PlixP.Repositories.Contracts
{
public interface IRepositoryWrapper
{
IBaseRepository<T> SetRepository<T>() where T : Entity;
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PlixP.Models;
using PlixP.Repositories.Contracts;
namespace PlixP.Repositories
{
public class RepositoryWrapper : IRepositoryWrapper
{
private readonly PlixContext _context;
public RepositoryWrapper(PlixContext context)
{
_context = context;
}
public IBaseRepository<T> SetRepository<T>() where T : Entity
{
IBaseRepository<T> repository = new BaseRepository<T>(_context);
return repository;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Plugin.Settings;
namespace PlixP.Services
{
public static class CatcherKeys
{
public static string MovieList { get; } = "Movies";
}
public class CatcherService
{
public void Set(object item, string key = null)
{
if (string.IsNullOrEmpty(key))
{
key = item.GetType().Name;
}
var json = JsonConvert.SerializeObject(item,Formatting.None, new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
Plugin.Settings.CrossSettings.Current.AddOrUpdateValue(key, json);
}
public T Get<T>(string key = null)
{
if (string.IsNullOrEmpty(key))
key = typeof(T).Name;
var json = CrossSettings.Current.GetValueOrDefault(key, string.Empty);
if (string.IsNullOrEmpty(json))
return Activator.CreateInstance<T>();
return JsonConvert.DeserializeObject<T>(json);
}
public void Delete<T>(string key = null)
{
if (string.IsNullOrEmpty(key))
key = typeof(T).Name;
CrossSettings.Current.Remove(key);
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PlixP.Services.Contracts
{
public interface IServiceWrapper
{
LocalServices LocalServices { get; }
MovieServices MovieServices { get; }
CatcherService CatcherService { get; }
}
}

View File

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace PlixP.Services
{
public class LocalServices
{
private string[] extentions = { ".mp4", ".mkv", ".avi" };
private List<DirectoryInfo> _baseDires = new List<DirectoryInfo>();
private List<string> paths = new List<string>();
public LocalServices()
{
var pathsJson = Plugin.Settings.CrossSettings.Current.GetValueOrDefault("Paths", string.Empty);
paths = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(pathsJson);
if (paths == null)
paths = new List<string>();
if (paths.Count > 0)
paths.ForEach(p => _baseDires.Add(new DirectoryInfo(p)));
}
public void ResetFolder()
{
RenameAllFile(GetMovieFiles());
CreateUnFolders(GetMovieFiles());
RenameAllFolder();
}
public string GetFolderNameByMovieFileName(string movieN)
{
string movieName = string.Empty;
bool yeared = false;
bool qualited = false;
movieN = movieN.Replace('-', '.');
movieN = movieN.Replace('_', '.');
foreach (var str in movieN.Split('.'))
{
int year = 0;
if (int.TryParse(str, out year) && (year >= 1920 && year <= 2142))
{
movieName += "(" + year + ")" + " ";
yeared = true;
}
else if (str.Contains("720") || str.Contains("1080") || str.ToLower().Contains("dvdsrc") || str.ToLower().Contains("hdrip") || str.ToLower().Contains("dvdrip"))
{
movieName += "[" + str + "]";
qualited = true;
}
else if (!yeared && !qualited)
{
movieName += str + " ";
}
}
return movieName;
}
private void RenameAllFolder()
{
try
{
if (paths.Count > 0)
{
foreach (var path in paths)
{
DirectoryInfo directoryInfo = new DirectoryInfo(path);
string baseDire = directoryInfo.Name;
var dires = GetDirectoryInfos(directoryInfo);
foreach (var dir in dires)
{
string movieN = string.Empty;
string movieName = string.Empty;
foreach (var fileInfo in dir.GetFiles())
{
if (fileInfo.Name.Contains(extentions[0]) || fileInfo.Name.Contains(extentions[1]) || fileInfo.Name.Contains(extentions[2]))
movieN = fileInfo.Name;
}
if (!string.IsNullOrEmpty(movieN))
{
movieName = GetFolderNameByMovieFileName(movieN);
DirectoryInfo di = new DirectoryInfo(string.Concat(dir.Parent, "\\", movieName));
if (!di.Exists)
Directory.Move(dir.FullName, string.Concat(dir.Parent, "\\", movieName));
}
}
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
public List<FileInfo> GetMovieFiles()
{
if (paths.Count > 0)
{
var allFiles = new List<FileInfo>();
foreach (var path in paths)
{
DirectoryInfo dir = new DirectoryInfo(path);
string baseDire = dir.Name;
var dires = GetDirectoryInfos(dir);
List<FileInfo> files = new List<FileInfo>();
foreach (var directoryInfo in dires)
{
files.AddRange(directoryInfo.GetFiles());
}
allFiles.AddRange(files);
}
return allFiles.Where(f => extentions.Contains(f.Extension)).ToList();
}
else
return new List<FileInfo>();
}
public void RenameAllFile(List<FileInfo> fileInfos)
{
fileInfos.ForEach(m =>
{
string newName = "";
foreach (var str in m.DirectoryName.Split("\\"))
{
newName += str + "\\";
}
var name = m.Name.Replace('_', '.');
name = name.Replace(' ', '.');
newName += name;
File.Move(m.FullName, newName);
});
}
public void CreateUnFolders(List<FileInfo> movies)
{
foreach (var baseDire in _baseDires)
{
movies.Where(m => m.DirectoryName.Split('\\').Last() == baseDire.Name).ToList().ForEach(m =>
{
try
{
string movieName = "";
bool yeared = false;
bool qualited = false;
foreach (var str in m.Name.Split('.'))
{
int year = 0;
if (int.TryParse(str, out year) && (year >= 1920 && year <= 2142))
{
movieName += "(" + year + ")" + " ";
yeared = true;
}
else if (str.Contains("720") || str.Contains("1080") || str.ToLower().Contains("dvdsrc") || str.ToLower().Contains("hdrip") || str.ToLower().Contains("dvdrip"))
{
movieName += "[" + str + "]";
qualited = true;
}
else if (!yeared && !qualited && !extentions.Contains(str))
{
movieName += str + " ";
}
}
var newDire = Path.Combine(m.DirectoryName, movieName).Trim();
Directory.CreateDirectory(newDire);
var orgFile = m.FullName;
var desFile = Path.Combine(newDire, m.Name);
File.Move(orgFile, desFile);
}
catch (Exception e)
{
Console.WriteLine(e);
MessageBox.Show(e.Message);
}
});
}
}
public List<DirectoryInfo> GetDirectoryInfos(DirectoryInfo baseDirectoryInfo)
{
try
{
List<DirectoryInfo> directoryInfos = new List<DirectoryInfo>();
var dires = baseDirectoryInfo.GetDirectories();
if (dires.Length > 0)
{
foreach (var directory in dires)
{
directoryInfos.AddRange(GetDirectoryInfos(directory));
}
}
directoryInfos.Add(baseDirectoryInfo);
return directoryInfos;
}
catch (Exception e)
{
Console.WriteLine(e);
return new List<DirectoryInfo>();
}
}
public void RenameFile(FileInfo oldFile, FileInfo newFile)
{
File.Move(oldFile.FullName, newFile.FullName);
}
public void RenameDirection(DirectoryInfo oldDirectory, DirectoryInfo newDirectory)
{
Directory.Move(oldDirectory.FullName, newDirectory.FullName);
}
}
}

View File

@ -0,0 +1,389 @@
using RestSharp;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using AutoMapper.QueryableExtensions;
using HandyControl.Controls;
using MaterialDesignThemes.Wpf;
using Microsoft.EntityFrameworkCore;
using PlixP.Models;
using PlixP.Repositories;
using PlixP.ViewModels;
using PlixP.Views.Dialogs;
using MessageBox = HandyControl.Controls.MessageBox;
using Timer = System.Timers.Timer;
namespace PlixP.Services
{
public class MovieServiceRealTime
{
private static MovieServiceRealTime _instance;
public static MovieServiceRealTime Instance
{
get
{
if (_instance == null)
_instance = new MovieServiceRealTime();
return _instance;
}
}
private LocalServices _localServices;
private MovieServices _movieServices;
private bool IsWorking = false;
private List<FileInfo> _currentFiles = new List<FileInfo>();
private Timer timer;
public List<Movie> CurreMovies
{
get { return _movieServices.GetMovies().Result; }
}
public MovieServiceRealTime()
{
timer = new Timer(6000);
_localServices = new LocalServices();
_movieServices = new MovieServices();
timer.Elapsed += Timer_Elapsed;
}
public void StartReal() => timer.Start();
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
CheckAll();
}
private async Task CheckAll()
{
try
{
if (IsWorking)
return;
IsWorking = true;
_localServices.ResetFolder();
var movieFolders = _localServices.GetMovieFiles();
foreach (var f in movieFolders)
{
if (!CurreMovies.Any(m => m.Location == f.DirectoryName))
{
await _movieServices.AddNewMovieToDb(f);
Application.Current.Dispatcher.Invoke(() =>
{
Growl.SuccessGlobal("Movie Added : " + f.Name);
});
}
}
foreach (var m in CurreMovies.Where(m => m.SyncStatus == SyncStatus.NotSynced))
{
var creationDate = m.CreationDate;
var movie = await _movieServices.GetMovieAsync(m.Title);
if (movie != null)
{
movie.CreationDate = creationDate;
movie.Id = m.Id;
movie.Location = m.Location;
movie.FileName = m.FileName;
movie.SyncStatus = SyncStatus.Synced;
await _movieServices.EditMovie(movie, SyncStatus.Synced);
Application.Current.Dispatcher.Invoke(() =>
{
Growl.WarningGlobal("Movie Synced : " + movie.FullName);
});
}
}
IsWorking = false;
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
public class MovieServices
{
private readonly RepositoryWrapper _repositoryWrapper;
private readonly LocalServices _localServices;
private readonly CatcherService _catcherService;
public MovieServices()
{
_repositoryWrapper = new RepositoryWrapper(new PlixContext());
_localServices = new LocalServices();
_catcherService = new CatcherService();
}
public async Task<List<Movie>> GetMovies()
{
try
{
List<Movie> Movies = new List<Movie>();
Movies = _catcherService.Get<List<Movie>>(CatcherKeys.MovieList);
if (Movies != null)
if (Movies.Count != 0)
return Movies;
var dtos = _repositoryWrapper.SetRepository<Movie>()
.TableNoTracking
.ProjectTo<MovieDto>()
.ToList();
dtos.ForEach(m => Movies.Add(m.ToEntity()));
foreach (var movie in Movies)
{
foreach (var categoryMovie in movie.Category)
{
categoryMovie.Category = await _repositoryWrapper.SetRepository<Category>()
.GetByIdAsync(CancellationToken.None, categoryMovie.CategoryId);
}
}
_catcherService.Set(Movies, CatcherKeys.MovieList);
return Movies;
}
catch (Exception e)
{
throw e;
}
}
public async Task<Movie> AddNewMovieToDb(FileInfo f)
{
var cMovie = new Movie();
var mName = f.Directory.Name.Split("(")[0];
cMovie = await GetMovieAsync(mName);
string q = " ";
if (f.Name.Contains("720"))
q = "720P";
else if (f.Name.Contains("1080"))
q = "1080P";
if (cMovie != null)
{
cMovie.FileName = f.Name;
cMovie.Location = f.DirectoryName;
cMovie.Quality = q;
cMovie.SyncStatus = SyncStatus.Synced;
cMovie.CreationDate = DateTime.Now;
await _repositoryWrapper.SetRepository<Movie>().AddAsync(cMovie, CancellationToken.None);
await _repositoryWrapper.SetRepository<CategoryMovie>().AddAsync(new CategoryMovie
{
MovieId = cMovie.Id,
CategoryId = 1
}, CancellationToken.None);
}
else
{
cMovie = new Movie();
cMovie.Location = f.DirectoryName;
cMovie.FileName = f.Name;
cMovie.Quality = q;
cMovie.Title = mName;
cMovie.CreationDate = DateTime.Now;
cMovie.SyncStatus = SyncStatus.NotSynced;
await _repositoryWrapper.SetRepository<Movie>().AddAsync(cMovie, CancellationToken.None);
await _repositoryWrapper.SetRepository<CategoryMovie>().AddAsync(new CategoryMovie
{
MovieId = cMovie.Id,
CategoryId = 1
}, CancellationToken.None);
}
_catcherService.Delete<List<Movie>>(CatcherKeys.MovieList);
return cMovie;
}
public async Task<Movie> GetMovieAsync(string movieName)
{
RestClient client = new RestClient();
RestRequest request = new RestRequest("http://omdbapi.com", Method.GET);
request.AddQueryParameter("t", movieName);
request.AddQueryParameter("apikey", "a915dcc9");
var res = await client.ExecuteGetAsync<Movie>(request);
if (res.StatusCode == HttpStatusCode.OK)
{
if (res.Data.Response != "False")
return res.Data;
else
{
/*Application.Current.Dispatcher.Invoke(() =>
{
Growl.ErrorGlobal($"Cant Sync Movie {movieName} , Please Edit Movie Detail");
});*/
return null;
}
}
else
{
/*Application.Current.Dispatcher.Invoke(() =>
{
Growl.ErrorGlobal($"Cant Sync Movie {movieName} , Please Edit Movie Detail");
});*/
return null;
}
}
public async Task EditMovie(Movie newMovie, SyncStatus syncStatus = SyncStatus.NotSynced)
{
try
{
var oldMovie = await _repositoryWrapper.SetRepository<Movie>()
.GetByIdAsync(CancellationToken.None, newMovie.Id);
string newMovieFileName = string.Empty;
foreach (var str in newMovie.Title.Split(" "))
{
if (string.IsNullOrWhiteSpace(str))
continue;
newMovieFileName += str + ".";
}
if (!string.IsNullOrWhiteSpace(newMovie.Year))
newMovieFileName += newMovie.Year + ".";
else
{
foreach (var str in oldMovie.FileName.Split("."))
{
int year = 0;
if (int.TryParse(str, out year) && (year >= 1920 && year <= 2142))
{
newMovieFileName += year + ".";
}
}
}
if (!string.IsNullOrWhiteSpace(newMovie.Quality))
newMovieFileName += newMovie.Quality + ".";
else
{
bool qulited = false;
foreach (var str in oldMovie.FileName.Split("."))
{
if (str.Contains("720") || str.Contains("1080") || str.ToLower().Contains("dvdsrc") || str.ToLower().Contains("hdrip") || str.ToLower().Contains("dvdrip"))
{
newMovieFileName += str + ".";
newMovie.Quality = str;
qulited = true;
}
}
if (!qulited)
{
newMovieFileName += "720" + ".";
newMovie.Quality = "720";
}
}
newMovieFileName += oldMovie.FileName.Split(".").Last();
newMovie.FileName = newMovieFileName;
newMovie.FileName = newMovie.FileName.Replace(":", "");
newMovie.FileName = newMovie.FileName.Replace(@"\", "");
newMovie.FileName = newMovie.FileName.Replace("?", "");
newMovie.FileName = newMovie.FileName.Replace("*", "");
newMovie.FileName = newMovie.FileName.Replace("/", "");
newMovie.FileName = newMovie.FileName.Replace("<", "");
newMovie.FileName = newMovie.FileName.Replace(">", "");
newMovie.FileName = newMovie.FileName.Replace("|", "");
var folderName = _localServices.GetFolderNameByMovieFileName(newMovie.FileName);
var location = Path.Combine(newMovie.Location.Split("\\").Take(newMovie.Location.Split("\\").Length - 1)
.ToArray());
newMovie.Location = $"{Path.Combine(location, folderName)}";
newMovie.SyncStatus = syncStatus;
newMovie.Category = null;
await _repositoryWrapper.SetRepository<Movie>().UpdateAsync(newMovie, CancellationToken.None);
if (oldMovie.Location != newMovie.Location)
_localServices.RenameDirection(new DirectoryInfo(oldMovie.Location), new DirectoryInfo(newMovie.Location));
oldMovie.Location = Path.Combine(location, folderName);
_localServices.RenameFile(new FileInfo(oldMovie.FullName), new FileInfo(newMovie.FullName));
_catcherService.Delete<List<Movie>>(CatcherKeys.MovieList);
MessageBox.Show($"Movie {newMovie.Title} Was Edited !");
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
public async Task<Dictionary<string, int>> GetGenres()
{
List<Movie> Movies = await GetMovies();
var originalGenres = Movies.Select(m => m.Genre).ToList();
Dictionary<string, int> genres = new Dictionary<string, int>();
foreach (var originalGenre in originalGenres)
{
if (string.IsNullOrEmpty(originalGenre))
continue;
var split = originalGenre.Split(',');
foreach (var str in split)
{
var trim = str.Trim();
if (genres.ContainsKey(trim))
genres[trim]++;
else
genres.Add(trim, 1);
}
}
return genres;
}
public async Task<List<GenreItemModel>> GetGenresModel()
{
List<Movie> Movies = await GetMovies();
var originalGenres = Movies.Select(m => m.Genre).ToList();
List<GenreItemModel> genres = new List<GenreItemModel>();
foreach (var originalGenre in originalGenres)
{
if (string.IsNullOrEmpty(originalGenre))
continue;
var split = originalGenre.Split(',');
foreach (var str in split)
{
var trim = str.Trim();
var genre = genres.FirstOrDefault(g=>g.Name==trim);
if (genre!=null)
genre.MovieCount++;
else
{
var item = new GenreItemModel
{
MovieCount = 1,
Name = trim
};
foreach (var movie in Movies.Where(m=>m.Genre.Contains(trim)))
{
var poster = movie.Poster;
if (!genres.Any(g => g.Image == poster))
item.Image = poster;
}
if (item.Image == null)
item.Image = Movies.FirstOrDefault(m => m.Genre.Contains(trim))?.Poster;
genres = genres.OrderByDescending(g => g.MovieCount).ToList();
genres.Add(item);
}
}
}
return genres;
}
public async Task<List<Movie>> SelectByGenre(string genre)
{
return (await GetMovies()).Where(m => m.Genre.Contains(genre))
.ToList();
}
public async Task DeleteMovie(Movie movie)
{
movie.Category = null;
await _repositoryWrapper.SetRepository<Movie>()
.DeleteAsync(movie, CancellationToken.None);
_catcherService.Delete<List<Movie>>(CatcherKeys.MovieList);
MovieServiceRealTime.Instance.CurreMovies.RemoveAll(m => m.Id == movie.Id);
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PlixP.Services.Contracts;
namespace PlixP.Services
{
public class ServiceWrapper : IServiceWrapper
{
private LocalServices _localServices;
public LocalServices LocalServices
{
get
{
if (_localServices == null)
_localServices = new LocalServices();
return _localServices;
}
}
private MovieServices _movieServices;
public MovieServices MovieServices
{
get
{
if (_movieServices == null)
_movieServices = new MovieServices();
return _movieServices;
}
}
private CatcherService _catcherService;
public CatcherService CatcherService
{
get
{
if (_catcherService == null)
_catcherService = new CatcherService();
return _catcherService;
}
}
}
}

View File

@ -0,0 +1,16 @@
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PlixP.ViewModels
{
public class AddCategoryDialogViewModel : BindableBase
{
public AddCategoryDialogViewModel()
{
}
}
}

View File

@ -0,0 +1,45 @@
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using PlixP.Repositories.Contracts;
using PlixP.Services.Contracts;
namespace PlixP.ViewModels
{
public class GenreItemModel
{
public string Name { get; set; }
public int Id { get; set; }
public string Image { get; set; }
public int MovieCount { get; set; }
}
public class GenresDialogViewModel : BindableBase
{
private readonly IServiceWrapper _serviceWrapper;
private readonly IRepositoryWrapper _repositoryWrapper;
public event EventHandler<string> GenreSelected;
public ICommand GenreSelectCommand { get; set; }
public ObservableCollection<GenreItemModel> Genres { get; set; } = new ObservableCollection<GenreItemModel>();
public GenresDialogViewModel(IServiceWrapper serviceWrapper,IRepositoryWrapper repositoryWrapper)
{
_serviceWrapper = serviceWrapper;
_repositoryWrapper = repositoryWrapper;
GenreSelectCommand = new DelegateCommand<GenreItemModel>(model =>
{
GenreSelected?.Invoke(model, model.Name);
});
Initialize();
}
private async Task Initialize()
{
(await _serviceWrapper.MovieServices.GetGenresModel()).ForEach(g=>Genres.Add(g));
}
}
}

View File

@ -0,0 +1,45 @@
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using PlixP.Services.Contracts;
using PlixP.Views;
using Prism.Mvvm;
using Prism.Regions;
namespace PlixP.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private string _title = "Prism Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
private int _count;
public int Count
{
get { return _count; }
set { SetProperty(ref _count, value); }
}
private string _background;
public string Background
{
get { return _background; }
set { SetProperty(ref _background, value); }
}
public MainWindowViewModel(IServiceWrapper serviceWrapper , IRegionManager regionManager)
{
var bg = Plugin.Settings.CrossSettings.Current.GetValueOrDefault("Background", string.Empty);
if (string.IsNullOrEmpty(bg))
Background = "https://www.jakpost.travel/wimages/large/166-1664172_lord-of-the-rings-background.jpg";
else
Background = bg;
}
}
}

View File

@ -0,0 +1,107 @@
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Timers;
using System.Windows;
using MaterialDesignThemes.Wpf;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using Microsoft.Xaml.Behaviors.Core;
using PlixP.Models;
using PlixP.Repositories.Contracts;
using PlixP.Services.Contracts;
using PlixP.Views;
using PlixP.Views.Dialogs;
namespace PlixP.ViewModels
{
public class MasterDetailViewModel : BindableBase
{
public ObservableCollection<string> Paths { get; set; } = new ObservableCollection<string>();
public DelegateCommand<string> PathCommand { get; set; }
public DelegateCommand<string> AddCategoryCommand { get; set; }
public DelegateCommand ResetFolderCommand { get; set; }
public DelegateCommand ChangeBackGroundCommand { get; set; }
public DelegateCommand<string> RemovePathCommand { get; set; }
public DelegateCommand ResetDbCommand { get; set; }
public MasterDetailViewModel(IRepositoryWrapper repositoryWrapper, IServiceWrapper serviceWrapper)
{
var pathsJson = Plugin.Settings.CrossSettings.Current.GetValueOrDefault("Paths", string.Empty);
if (!string.IsNullOrEmpty(pathsJson))
{
var paths = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(pathsJson);
if (paths != null)
paths.ForEach(p => Paths.Add(p));
}
PathCommand = new DelegateCommand<string>((str) =>
{
if (!string.IsNullOrEmpty(str))
{
Paths.Add(str);
var pathJson = Newtonsoft.Json.JsonConvert.SerializeObject(Paths.ToList());
Plugin.Settings.CrossSettings.Current.AddOrUpdateValue("Paths", pathJson);
MessageBox.Show("Seccuss");
//serviceWrapper.LocalServices.ResetFolder();
}
});
ResetDbCommand = new DelegateCommand(() =>
{
QuestionDialog dialog = new QuestionDialog("ایا از ریست کردن دیتابیس مطمئن هستید ؟");
dialog.Submited += (async (ss, ee) =>
{
var context = new PlixContext();
await context.Database.EnsureDeletedAsync();
await context.Database.MigrateAsync();
});
DialogHost.OpenDialogCommand.Execute(dialog,null);
});
RemovePathCommand = new DelegateCommand<string>(str =>
{
Paths.Remove(str);
var pathJson = Newtonsoft.Json.JsonConvert.SerializeObject(Paths.ToList());
Plugin.Settings.CrossSettings.Current.AddOrUpdateValue("Paths", pathJson);
MessageBox.Show("Seccuss");
});
AddCategoryCommand = new DelegateCommand<string>(async(cat) =>
{
try
{
await repositoryWrapper.SetRepository<Category>().AddAsync(new Category
{
Name = cat
},CancellationToken.None);
MessageBox.Show("Seccuss");
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
});
ResetFolderCommand = new DelegateCommand(() =>
{
serviceWrapper.LocalServices.ResetFolder();
});
ChangeBackGroundCommand = new DelegateCommand( ()=>
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = false;
openFileDialog.Filter = "Image Files(*.BMP;*.JPG;*.GIF*.PNG)|*.BMP;*.JPG;*.GIF*.PNG|All files (*.*)|*.*";
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (openFileDialog.ShowDialog() == true)
{
var str = openFileDialog.FileName;
if (!string.IsNullOrEmpty(str))
{
Plugin.Settings.CrossSettings.Current.AddOrUpdateValue("Background", str);
DialogHost.OpenDialogCommand.Execute(new RestartAppDialog(),null);
}
}
});
}
}
}

View File

@ -0,0 +1,162 @@
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows.Input;
using HandyControl.Controls;
using HandyControl.Interactivity;
using MaterialDesignThemes.Wpf;
using Microsoft.EntityFrameworkCore;
using PlixP.Models;
using PlixP.Repositories.Contracts;
using PlixP.Services;
using PlixP.Services.Contracts;
using PlixP.Views.Dialogs;
using MessageBox = System.Windows.MessageBox;
namespace PlixP.ViewModels
{
public class MovieDialogViewModel : BindableBase
{
private Movie _movie;
public Movie Movie
{
get { return _movie; }
set { SetProperty(ref _movie, value); }
}
public ICommand DeleteCommand { get; set; }
public ICommand SaveCommand { get; set; }
public ICommand PlayFileCommand { get; set; }
public ICommand OpenFolderCommand { get; set; }
public ICommand AddCategoryCommand { get; set; }
public ICommand RemoveCategoryCommand { get; set; }
private IServiceWrapper ServiceWrapper { get; set; }
private IRepositoryWrapper RepositoryWrapper { get; set; }
public ObservableCollection<Category> Categories { get; set; }
public List<object> Properties { get; set; } = new List<object>();
public MovieDialogViewModel()
{
}
public MovieDialogViewModel(IServiceWrapper serviceWrapper, IRepositoryWrapper repositoryWrapper, Movie movie)
{
Categories = new ObservableCollection<Category>();
repositoryWrapper.SetRepository<Category>().TableNoTracking.ToList().ForEach(c => Categories.Add(c));
Movie = movie;
ServiceWrapper = serviceWrapper;
RepositoryWrapper = repositoryWrapper;
Properties.Add(new
{
Name = "Director : ",
Value = movie.Director
});
Properties.Add(new
{
Name = "Writer : ",
Value = movie.Writer
});
Properties.Add(new
{
Name = "Awarads : ",
Value = movie.Awards
});
Properties.Add(new
{
Name = "Actors : ",
Value = movie.Actors
});
Properties.Add(new
{
Name = "Country : ",
Value = movie.Country
});
DeleteCommand = new DelegateCommand(() =>
{
QuestionDialog dialog = new QuestionDialog("ایا از حذف فیلم مطمئن هستید ؟");
dialog.Submited += (async (ss, ee) =>
{
await serviceWrapper.MovieServices.DeleteMovie(movie);
ControlCommands.CloseAll.Execute(null, null);
HandyControl.Controls.MessageBox.Show($"{movie.Title} Has Removed");
});
Dialog.Show(dialog);
});
PlayFileCommand = new DelegateCommand(() =>
{
Process process = new Process();
process.StartInfo.UseShellExecute = true;
process.StartInfo.FileName = @Movie.Location + "\\" + Movie.FullName;
process.Start();
});
OpenFolderCommand = new DelegateCommand(() =>
{
try
{
Process process = new Process();
process.StartInfo.UseShellExecute = true;
process.StartInfo.FileName = @Movie.Location;
process.Start();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
});
AddCategoryCommand = new DelegateCommand<Category>(async (category) =>
{
if (category.Id != 0)
{
if (Movie.Category.FirstOrDefault(c => c.CategoryId == category.Id) == null)
{
Movie.Category.Add(new CategoryMovie
{
MovieId = Movie.Id,
Category = category,
CategoryId = category.Id
});
await repositoryWrapper.SetRepository<CategoryMovie>().AddAsync(new CategoryMovie
{
MovieId = Movie.Id,
CategoryId = category.Id
},CancellationToken.None);
}
}
else
{
Movie.Category.Add(new CategoryMovie
{
MovieId = Movie.Id,
Category = category
});
await repositoryWrapper.SetRepository<CategoryMovie>().AddAsync(new CategoryMovie
{
MovieId = Movie.Id,
Category = category
},CancellationToken.None);
}
});
RemoveCategoryCommand = new DelegateCommand<CategoryMovie>(async (cMovie)=>
{
try
{
await RepositoryWrapper.SetRepository<CategoryMovie>().DeleteAsync(cMovie,CancellationToken.None);
Movie.Category.Remove(cMovie);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
});
SaveCommand = new DelegateCommand<Movie>(async (m) =>
{
await ServiceWrapper.MovieServices.EditMovie(m);
});
}
}
}

View File

@ -0,0 +1,18 @@
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace PlixP.ViewModels
{
public class MovieItemViewModel : BindableBase
{
public MovieItemViewModel()
{
}
}
}

View File

@ -0,0 +1,195 @@
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using HandyControl.Controls;
using MaterialDesignThemes.Wpf;
using PlixP.Models;
using PlixP.Repositories.Contracts;
using PlixP.Services.Contracts;
using PlixP.Views.Dialogs;
using MessageBox = HandyControl.Controls.MessageBox;
namespace PlixP.ViewModels
{
public class MovieListViewModel : BindableBase
{
private readonly IServiceWrapper _serviceWrapper;
private readonly IRepositoryWrapper _repositoryWrapper;
private int pagingCount = 25;
private int currentPage = 0;
public bool IsAllActive { get; set; } = true;
public MovieListModel MovieListModel { get; set; } = new MovieListModel();
public ICommand RefreshCommand { get; set; }
public ICommand CheckByRealease { get; set; }
public ICommand MovieSelectedCommand { get; set; }
public ICommand RefreshFilesCommand { get; set; }
public ICommand CheckByAddedCommand { get; set; }
public ICommand CheckByImdbCommand { get; set; }
public ICommand GenreSelectedCommand { get; set; }
public ICommand NextPageCommand { get; set; }
public ICommand SearchCommand { get; set; }
public MovieListViewModel(IServiceWrapper serviceWrapper, IRepositoryWrapper repositoryWrapper)
{
_serviceWrapper = serviceWrapper;
_repositoryWrapper = repositoryWrapper;
Initialize();
CheckByImdbCommand = new DelegateCommand(async () =>
{
ChangeByImdb();
});
RefreshCommand = new DelegateCommand(async () =>
{
//await _serviceWrapper.MovieServices.SyncMovies();
await Initialize();
IsAllActive = true;
});
MovieSelectedCommand = new DelegateCommand<Movie>((dataContext) =>
{
Dialog.Show(new MovieDialog() { DataContext = new MovieDialogViewModel(serviceWrapper, repositoryWrapper, dataContext) });
});
RefreshFilesCommand = new DelegateCommand(() =>
{
serviceWrapper.LocalServices.ResetFolder();
});
CheckByAddedCommand = new DelegateCommand(async () =>
{
await Initialize();
});
CheckByRealease = new DelegateCommand(() =>
{
ChangeByRelease();
});
GenreSelectedCommand = new DelegateCommand(() =>
{
var genreDialog = new GenresDialog(_serviceWrapper,_repositoryWrapper);
genreDialog.GenreSelected += (async (ss, genre) =>
{
await ChangeGenre(genre);
});
Dialog.Show(genreDialog);
});
SearchCommand = new DelegateCommand<string>(async (search) =>
{
try
{
MovieListModel.UnPagedMovies.Clear();
foreach (var originalMovie in MovieListModel.OriginalMovies)
{
if (originalMovie.Title.ToLower().Contains(search.ToLower()))
MovieListModel.UnPagedMovies.Add(originalMovie);
}
MovieListModel.PageMovies.Clear();
currentPage = 0;
Pagination();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
await Initialize();
}
});
NextPageCommand = new DelegateCommand(async () =>
{
currentPage++;
Pagination();
});
}
private void ChangeByImdb()
{
MovieListModel.UnPagedMovies.Clear();
MovieListModel.OriginalMovies.OrderByDescending(m =>
{
float rate;
if (float.TryParse(m.imdbRating, out rate))
return rate;
return 0;
}).ToList()
.ForEach(m => MovieListModel.UnPagedMovies.Add(m));
MovieListModel.PageMovies.Clear();
currentPage = 0;
Pagination();
}
private async Task ChangeGenre(List<string> genres)
{
MovieListModel.UnPagedMovies.Clear();
foreach (var genre in genres)
{
var moviesGenre = await _serviceWrapper.MovieServices.SelectByGenre(genre);
moviesGenre.ForEach(m => MovieListModel.UnPagedMovies.Add(m));
}
MovieListModel.PageMovies.Clear();
currentPage = 0;
}
private async Task ChangeGenre(string genre)
{
MovieListModel.UnPagedMovies.Clear();
var moviesGenre = await _serviceWrapper.MovieServices.SelectByGenre(genre);
moviesGenre.ForEach(m => MovieListModel.UnPagedMovies.Add(m));
MovieListModel.PageMovies.Clear();
currentPage = 0;
}
private async Task ChangeByRelease()
{
MovieListModel.UnPagedMovies.Clear();
MovieListModel.OriginalMovies.OrderByDescending(m => m.IntYear).ToList()
.ForEach(m => MovieListModel.UnPagedMovies.Add(m));
MovieListModel.PageMovies.Clear();
currentPage = 0;
Pagination();
}
private async Task Initialize()
{
MovieListModel.PageMovies.Clear();
MovieListModel.UnPagedMovies.Clear();
MovieListModel.OriginalMovies.Clear();
(await _serviceWrapper.MovieServices.GetMovies())
.OrderByDescending(m => m.CreationDate)
.ToList()
.ForEach(m =>
{
MovieListModel.OriginalMovies.Add(m);
});
MovieListModel.OriginalMovies.ToList()
.ForEach(m => MovieListModel.UnPagedMovies.Add(m));
MovieListModel.OriginalCategories = new ObservableCollection<Category>(_repositoryWrapper
.SetRepository<Category>().TableNoTracking);
MovieListModel.MoviesCount = MovieListModel.UnPagedMovies.Count;
MovieListModel.OriginalGenres = await _serviceWrapper.MovieServices.GetGenres();
currentPage = 0;
Pagination();
}
public void Pagination()
{
var selected = MovieListModel.UnPagedMovies.Skip((currentPage * pagingCount)).Take(pagingCount).ToList();
foreach (var movie in selected)
{
Application.Current.Dispatcher.Invoke(() =>
{
MovieListModel.PageMovies.Add(movie);
});
}
}
}
}

View File

@ -0,0 +1,16 @@
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PlixP.ViewModels
{
public class SuggestionBoxViewModel : BindableBase
{
public SuggestionBoxViewModel()
{
}
}
}

View File

@ -0,0 +1,15 @@
<UserControl
x:Class="PlixP.Views.Dialogs.AddCategoryDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
Width="350"
prism:ViewModelLocator.AutoWireViewModel="True"
Background="Transparent"
TextElement.FontSize="13"
TextElement.FontWeight="Regular"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto">
<materialDesign:Card Width="350" Padding="10" />
</UserControl>

View File

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace PlixP.Views.Dialogs
{
/// <summary>
/// Interaction logic for AddCategoryDialog
/// </summary>
public partial class AddCategoryDialog : UserControl
{
public AddCategoryDialog()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,101 @@
<UserControl
x:Class="PlixP.Views.Dialogs.GenresDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
xmlns:renders="clr-namespace:PlixP.Renders"
Width="870"
Height="700"
prism:ViewModelLocator.AutoWireViewModel="True">
<materialDesign:Card
Padding="15"
materialDesign:ShadowAssist.ShadowDepth="Depth5"
Background="{StaticResource SecondaryRegionBrush}"
UniformCornerRadius="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock FontSize="24" Text="Genres" />
<Button
Grid.Column="1"
Margin="0,0,0,0"
Padding="9,8,0,0"
VerticalAlignment="Center"
Background="#FF5252"
BorderThickness="0"
Command="hc:ControlCommands.Close"
Foreground="White"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}">
<materialDesign:PackIcon
Width="24"
Height="24"
Kind="Close" />
</Button>
</Grid>
<hc:ScrollViewer
Grid.Row="1"
Margin="0,8,0,0"
Padding="0">
<ItemsControl
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
ItemsSource="{Binding Genres}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<materialDesign:Card
Margin="15"
materialDesign:ShadowAssist.ShadowDepth="Depth5"
Background="{StaticResource SecondaryRegionBrush}"
Cursor="{x:Static input:Cursors.Hand}"
MouseDown="GenreItem_OnMouseDown"
UniformCornerRadius="10">
<Grid>
<renders:ImageCacher
Width="250"
Height="150"
ImageSource="{Binding Path=Image}"
Stretch="UniformToFill" />
<Grid Background="#99222222">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock
HorizontalAlignment="Center"
FontSize="24"
FontWeight="Light"
Text="{Binding Name}" />
<TextBlock
HorizontalAlignment="Center"
FontSize="24"
FontWeight="Bold"
Foreground="{StaticResource PrimaryBrush}"
Text="{Binding MovieCount}" />
</StackPanel>
</Grid>
</Grid>
</materialDesign:Card>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</hc:ScrollViewer>
</Grid>
</materialDesign:Card>
</UserControl>

View File

@ -0,0 +1,39 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
using HandyControl.Controls;
using HandyControl.Interactivity;
using PlixP.Repositories.Contracts;
using PlixP.Services.Contracts;
using PlixP.ViewModels;
using Card = MaterialDesignThemes.Wpf.Card;
namespace PlixP.Views.Dialogs
{
/// <summary>
/// Interaction logic for GenresDialog
/// </summary>
public partial class GenresDialog : UserControl
{
public event EventHandler<string> GenreSelected;
public GenresDialog(IServiceWrapper serviceWrapper,IRepositoryWrapper repositoryWrapper)
{
var viewModel = new GenresDialogViewModel(serviceWrapper, repositoryWrapper);
DataContext = viewModel;
viewModel.GenreSelected += ((model, genre) =>
{
GenreSelected?.Invoke(model,genre);
ControlCommands.Close.Execute(this,this);
});
InitializeComponent();
}
private void GenreItem_OnMouseDown(object sender, MouseButtonEventArgs e)
{
if(sender is Card card && card.DataContext is GenreItemModel model && DataContext is GenresDialogViewModel viewModel)
viewModel.GenreSelectCommand.Execute(model);
}
}
}

View File

@ -0,0 +1,34 @@
<UserControl
x:Class="PlixP.Views.Dialogs.LoadingDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PlixP.Views.Dialogs"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="200"
d:DesignWidth="200"
Background="Transparent"
TextElement.FontSize="13"
TextElement.FontWeight="Regular"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
mc:Ignorable="d">
<materialDesign:Card
Padding="10"
materialDesign:ShadowAssist.ShadowDepth="Depth5"
UniformCornerRadius="10">
<StackPanel VerticalAlignment="Center">
<ProgressBar
Width="80"
Height="80"
IsIndeterminate="True"
Value="0" />
<TextBlock
Margin="0,15"
HorizontalAlignment="Center"
Text="Loading ...." />
</StackPanel>
</materialDesign:Card>
</UserControl>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace PlixP.Views.Dialogs
{
/// <summary>
/// Interaction logic for LoadingDialog.xaml
/// </summary>
public partial class LoadingDialog : UserControl
{
public LoadingDialog()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,337 @@
<UserControl
x:Class="PlixP.Views.Dialogs.MovieDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
xmlns:renders="clr-namespace:PlixP.Renders"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
Width="950"
prism:ViewModelLocator.AutoWireViewModel="True"
Background="Transparent"
TextElement.FontSize="13"
TextElement.FontWeight="Regular"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto">
<materialDesign:Card
materialDesign:ShadowAssist.ShadowDepth="Depth5"
Background="{StaticResource SecondaryRegionBrush}"
UniformCornerRadius="10">
<Grid>
<materialDesign:Card Padding="10" UniformCornerRadius="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<materialDesign:Card
Grid.Row="0"
Grid.Column="0"
UniformCornerRadius="10">
<renders:ImageCacher
Height="380"
HorizontalAlignment="Left"
VerticalAlignment="Top"
ImageSource="{Binding Path=Movie.Poster}" />
</materialDesign:Card>
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="0"
Margin="0,8,0,8"
VerticalAlignment="Center">
<TextBox
Name="titleTextBox"
Margin="8,0,0,5"
VerticalAlignment="Bottom"
FontSize="20"
FontWeight="Thin"
IsReadOnly="True"
Resources="{StaticResource Material}"
Text="{Binding Path=Movie.Title, Mode=OneWay}" />
<StackPanel
Margin="8"
VerticalAlignment="Top"
Orientation="Horizontal">
<hc:Shield
Status="{Binding Path=Movie.imdbRating}"
Subject="IMDB"
Color="#f39c12" />
<hc:Shield
Margin="8,0,0,0"
Status="{Binding Path=Movie.Metascore}"
Subject="Meta Score"
Color="#e67e22" />
<hc:Shield
Margin="8,0"
Status="{Binding Path=Movie.Released}"
Subject="Realease"
Color="#27ae60" />
<hc:Shield
Margin="0,0"
Status="{Binding Path=Movie.Quality}"
Subject="Quality"
Color="#2980b9" />
<hc:Shield
Margin="8,0"
Status="{Binding Path=Movie.BoxOffice}"
Subject="BoxOffice"
Color="#8e44ad" />
</StackPanel>
</StackPanel>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" Margin="8,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ItemsControl
x:Name="categoryItems"
Margin="0,10"
ItemsSource="{Binding Path=Movie.Category}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<hc:Tag
Content="{Binding Path=Category.Name}"
Foreground="#444"
IsSelected="True"
ShowCloseButton="True" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<materialDesign:PopupBox
Name="AddCategoryPopUp"
Grid.Column="1"
Margin="-45,0,0,-5"
IsEnabled="{Binding IsChecked, ElementName=PopupEnabled}"
StaysOpen="True"
Visibility="Hidden">
<materialDesign:Card Background="{StaticResource ThirdlyRegionBrush}" UniformCornerRadius="8">
<Grid Width="300" Margin="8,8,8,8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ComboBox
Name="categoryCombo"
Grid.Row="0"
Grid.Column="0"
Margin="8,8,8,8"
materialDesign:HintAssist.Hint="Categoreis"
materialDesign:HintAssist.IsFloating="True"
DisplayMemberPath="Name"
ItemsSource="{Binding Categories}"
MaxDropDownHeight="200" />
<StackPanel
Grid.Row="2"
HorizontalAlignment="Left"
Orientation="Horizontal">
<Button Click="AddCategoryButton_OnClick" Content="Add" />
<Button Command="{x:Static materialDesign:PopupBox.ClosePopupCommand}" Content="_Cancel" />
</StackPanel>
</Grid>
</materialDesign:Card>
</materialDesign:PopupBox>
<Button
Name="addCategoryButton"
Grid.Column="1"
Width="40"
Height="40"
Background="#40000000"
Click="AddCategoryButtonBase_OnClick"
Content="+"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignIconButton}" />
</Grid>
<StackPanel
Grid.Column="0"
VerticalAlignment="Center"
Orientation="Horizontal">
<CheckBox
x:Name="dubbedToggle"
Margin="8,0"
HorizontalAlignment="Left"
Content="DUBBED"
IsChecked="{Binding Path=Movie.IsDubbed, Mode=OneWay}" />
<CheckBox
x:Name="seenToggle"
Margin="0,2"
HorizontalAlignment="Left"
Content="IsSeen"
IsChecked="{Binding Path=Movie.IsSeen, Mode=OneWay}" />
</StackPanel>
</Grid>
<ItemsControl Grid.Row="2" ItemsSource="{Binding Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,5" Orientation="Horizontal">
<TextBlock
Padding="5"
HorizontalAlignment="Center"
FontSize="12"
FontWeight="Medium"
Text="{Binding Name}"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
<TextBlock
Padding="0,5"
HorizontalAlignment="Center"
FontSize="11"
FontWeight="Medium"
Text="{Binding Value}"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<Grid
Grid.Column="2"
Margin="5,5,0,5"
HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button
Width="40"
Height="40"
Margin="0,0,10,0"
Padding="5,7,0,0"
VerticalAlignment="Bottom"
Click="Edit_OnClick"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingActionMiniButton}">
<materialDesign:PackIcon Width="20" Kind="Pencil" />
</Button>
<Button
Margin="0,5,0,0"
Padding="9,8,0,0"
Background="#FF5252"
BorderThickness="0"
Command="hc:ControlCommands.Close"
Foreground="White"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}">
<materialDesign:PackIcon
Width="24"
Height="24"
Kind="Close" />
</Button>
</StackPanel>
<StackPanel
Grid.Row="1"
HorizontalAlignment="Right"
VerticalAlignment="Center">
<Button
Padding="12,5,0,0"
Command="{Binding OpenFolderCommand}"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignIconButton}">
<materialDesign:PackIcon Kind="AttachFile" />
</Button>
<Button
Width="60"
Height="60"
Padding="22,15,0,0"
Background="#40eeeeee"
Command="{Binding PlayFileCommand}"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignIconButton}">
<materialDesign:PackIcon
Width="35"
Height="35"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="DeepSkyBlue"
Kind="Play" />
</Button>
<Button
Padding="10,5,0,0"
Command="{Binding DeleteCommand}"
Foreground="#FF5252"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignIconButton}">
<materialDesign:PackIcon Kind="Delete" />
</Button>
</StackPanel>
</Grid>
</Grid>
<Grid Grid.Row="1" Margin="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Padding="5"
HorizontalAlignment="Center"
FontSize="12"
FontWeight="Medium"
Text="Plot : "
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
<TextBlock
Grid.Column="1"
Padding="0,5"
HorizontalAlignment="Center"
FontSize="11"
FontWeight="Medium"
Text="{Binding Path=Movie.Plot}"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
</Grid>
</Grid>
</materialDesign:Card>
</Grid>
</materialDesign:Card>
</UserControl>

View File

@ -0,0 +1,143 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using MaterialDesignThemes.Wpf;
using Microsoft.EntityFrameworkCore;
using PlixP.Models;
using PlixP.ViewModels;
namespace PlixP.Views.Dialogs
{
/// <summary>
/// Interaction logic for MovieDialog
/// </summary>
public partial class MovieDialog : UserControl
{
public Movie Movie
{
get
{
return (DataContext as MovieDialogViewModel).Movie;
}
}
public MovieDialog()
{
InitializeComponent();
seenToggle.Checked += SeenToggle_OnChecked;
dubbedToggle.Checked += DubbedToggle_OnChecked;
}
public MovieDialog(Movie dataContext)
{
InitializeComponent();
}
private void Edit_OnClick(object sender, RoutedEventArgs e)
{
var button = sender as Button;
button.Content = new PackIcon
{
Kind = PackIconKind.Check,
Width = 20
};
categoryItems.IsEnabled = true;
button.Click += AcceptEdit_Click;
titleTextBox.IsReadOnly = false;
dubbedToggle.IsEnabled = true;
seenToggle.IsEnabled = true;
addCategoryButton.IsEnabled = true;
}
private void AcceptEdit_Click(object sender, RoutedEventArgs e)
{
try
{
Movie newMovie = (DataContext as MovieDialogViewModel)?.Movie.Clone() as Movie;
if (Movie.Title != null && !Movie.Title.Equals(titleTextBox.Text))
{
newMovie.Title = titleTextBox.Text;
}
if (Movie.IsDubbed != dubbedToggle.IsChecked)
{
if (dubbedToggle.IsChecked == true)
{
var newName = Movie.FileName.Split('.');
string nn = "";
for (int i = 0; i < newName.Length; i++)
{
if (i == newName.Length - 1)
{
nn += "Dubbed" + ".";
}
nn += newName[i] + ".";
}
newMovie.FileName = nn;
}
else
{
var newName = Movie.FileName.Replace("Dubbed.", "");
newMovie.FileName = newName;
}
}
if (Movie.IsSeen != seenToggle.IsChecked)
{
newMovie.IsSeen = seenToggle.IsChecked ?? false;
}
(DataContext as MovieDialogViewModel)?.SaveCommand.Execute(newMovie);
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
}
private void DubbedToggle_OnChecked(object sender, RoutedEventArgs e)
{
var toggel = sender as CheckBox;
if (!categoryItems.IsEnabled)
toggel.IsChecked = !toggel.IsChecked;
}
private void SeenToggle_OnChecked(object sender, RoutedEventArgs e)
{
var toggel = sender as CheckBox;
if (!categoryItems.IsEnabled)
toggel.IsChecked = !toggel.IsChecked;
}
private void AddCategoryButtonBase_OnClick(object sender, RoutedEventArgs e)
{
if (!AddCategoryPopUp.IsPopupOpen)
AddCategoryPopUp.IsPopupOpen = true;
else
AddCategoryPopUp.IsPopupOpen = false;
}
private void CategoryNameTextBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
categoryCombo.IsEnabled = true;
}
private void AddCategoryButton_OnClick(object sender, RoutedEventArgs e)
{
if (categoryCombo.SelectedValue != null)
{
var category = categoryCombo.SelectedValue as Category;
(DataContext as MovieDialogViewModel)?.AddCategoryCommand.Execute(category);
}
}
private void RemoveCategoryButton_OnClick(object sender, RoutedEventArgs e)
{
(DataContext as MovieDialogViewModel)?.RemoveCategoryCommand.Execute((sender as Button).DataContext);
}
}
}

View File

@ -0,0 +1,49 @@
<UserControl
x:Class="PlixP.Views.Dialogs.QuestionDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:PlixP.Views.Dialogs"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<materialDesign:Card
Padding="50,20"
materialDesign:ShadowAssist.ShadowDepth="Depth5"
Background="{StaticResource RegionBrush}"
UniformCornerRadius="10">
<Grid>
<StackPanel Margin="15">
<TextBlock
Name="messageTextBlock"
HorizontalAlignment="Center"
FontSize="18"
FontWeight="Black"
Text="برای ایجاد تغییرات لطفا برنامه را ری استارت کنید" />
<StackPanel
Margin="0,55,0,0"
HorizontalAlignment="Center"
Orientation="Horizontal">
<Button
HorizontalAlignment="Center"
Command="hc:ControlCommands.Close"
CommandParameter="Sample2Cancel"
Content="انصراف"
IsCancel="True"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignOutlinedButton}" />
<Button
Margin="15,0,15,0"
HorizontalContentAlignment="Center"
Click="SubmitButtonBase_OnClick"
Content="تایــــــید"
IsCancel="False"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignRaisedButton}" />
</StackPanel>
</StackPanel>
</Grid>
</materialDesign:Card>
</UserControl>

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using HandyControl.Interactivity;
using MaterialDesignThemes.Wpf;
namespace PlixP.Views.Dialogs
{
/// <summary>
/// Interaction logic for QuestionDialog.xaml
/// </summary>
public partial class QuestionDialog : UserControl
{
public event EventHandler Submited;
public QuestionDialog(string message)
{
InitializeComponent();
messageTextBlock.Text = message;
}
private void SubmitButtonBase_OnClick(object sender, RoutedEventArgs e)
{
ControlCommands.Close.Execute(null,null);
Submited?.Invoke(this,new EventArgs());
}
}
}

View File

@ -0,0 +1,40 @@
<UserControl
x:Class="PlixP.Views.Dialogs.RestartAppDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PlixP.Views.Dialogs"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
TextElement.FontSize="13"
TextElement.FontWeight="Regular"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
mc:Ignorable="d">
<Grid>
<StackPanel Margin="15">
<TextBlock
HorizontalAlignment="Center"
FontSize="18"
Text="برای ایجاد تغییرات لطفا برنامه را ری استارت کنید" />
<StackPanel
Margin="0,20,0,0"
HorizontalAlignment="Center"
Orientation="Horizontal">
<Button
Margin="0,15"
HorizontalAlignment="Center"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="Sample2Cancel"
Content="انصراف"
IsCancel="True" />
<Button
Margin="0,15"
HorizontalContentAlignment="Center"
Click="SubmitButtonBase_OnClick"
Content="تایید" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace PlixP.Views.Dialogs
{
/// <summary>
/// Interaction logic for RestartAppDialog.xaml
/// </summary>
public partial class RestartAppDialog : UserControl
{
public RestartAppDialog()
{
InitializeComponent();
}
private void SubmitButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Process.Start(Process.GetCurrentProcess().MainModule.FileName);
Application.Current.Shutdown();
}
}
}

View File

@ -0,0 +1,46 @@
<hc:Window
x:Class="PlixP.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
xmlns:renders="clr-namespace:PlixP.Renders"
xmlns:template="clr-namespace:PlixP.Views.Template"
xmlns:views="clr-namespace:PlixP.Views"
Title="Plix"
prism:ViewModelLocator.AutoWireViewModel="True"
Icon="../Resources/PlixLogo.ico"
ShowTitle="True"
WindowState="Maximized">
<materialDesign:DrawerHost>
<Grid x:Name="mainGrid">
<renders:ImageCacher ImageSource="{Binding Background}" Stretch="UniformToFill" />
<Grid Background="#10000000" />
<ContentControl prism:RegionManager.RegionName="ContentRegion" />
<StackPanel Orientation="Horizontal">
<Button
Width="50"
Height="50"
Margin="50,22,15,0"
Padding="8,15,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{x:Static materialDesign:DrawerHost.OpenDrawerCommand}"
CommandParameter="{x:Static Dock.Left}"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingActionMiniButton}">
<materialDesign:PackIcon
Width="30"
Height="30"
Kind="Menu" />
</Button>
</StackPanel>
</Grid>
<materialDesign:DrawerHost.LeftDrawerContent>
<views:MasterDetail />
</materialDesign:DrawerHost.LeftDrawerContent>
</materialDesign:DrawerHost>
</hc:Window>

View File

@ -0,0 +1,25 @@
using System;
using System.Windows;
using MaterialDesignThemes.Wpf;
using PlixP.Views.Dialogs;
using Prism.Regions;
using Window = HandyControl.Controls.Window;
namespace PlixP.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public static Snackbar snackbar = new Snackbar();
public MainWindow(IRegionManager regionManager)
{
InitializeComponent();
DialogHost.Show(new LoadingDialog());
regionManager.RegisterViewWithRegion("ContentRegion", typeof(MovieList));
mainGrid.Children.Add(snackbar);
}
}
}

View File

@ -0,0 +1,173 @@
<UserControl
x:Class="PlixP.Views.MasterDetail"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
Width="450"
Padding="5"
prism:ViewModelLocator.AutoWireViewModel="True"
Background="#444"
TextElement.FontSize="13"
TextElement.FontWeight="Regular"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto">
<StackPanel Margin="15">
<Grid Margin="0,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox
Name="addPathTextBox"
Grid.Column="0"
MinWidth="300"
Padding="5,3"
VerticalAlignment="Center"
Resources="{StaticResource Material}"
Text="{Binding Path}">
<materialDesign:HintAssist.Hint>
<StackPanel Margin="-2,0,0,0" Orientation="Horizontal">
<materialDesign:PackIcon Kind="Add" />
<TextBlock>
Path
</TextBlock>
</StackPanel>
</materialDesign:HintAssist.Hint>
</TextBox>
<Button
Grid.Column="1"
Margin="10,0"
HorizontalAlignment="Center"
Click="Path_OnClick"
Content="+"
Resources="{StaticResource Material}" />
</Grid>
<ItemsControl ItemsSource="{Binding Paths}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border
Margin="0,4"
Padding="5"
Background="#40444444">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Text="{Binding .}" />
<Button
Grid.Column="1"
Width="25"
Height="25"
Padding="5,4,0,0"
HorizontalAlignment="Left"
Background="OrangeRed"
BorderBrush="Transparent"
BorderThickness="0"
Click="RemovePathButtonBase_OnClick"
Foreground="White"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingActionButton}"
ToolTip="MaterialDesignFloatingActionMiniButton">
<materialDesign:PackIcon
Width="15"
Height="15"
Kind="Close" />
</Button>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid Margin="0,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox
Name="addCategoryTextBox"
Grid.Column="0"
Padding="5,3"
VerticalAlignment="Center"
Resources="{StaticResource Material}">
<materialDesign:HintAssist.Hint>
<StackPanel Margin="-2,0,0,0" Orientation="Horizontal">
<materialDesign:PackIcon Kind="Add" />
<TextBlock>
Add Category
</TextBlock>
</StackPanel>
</materialDesign:HintAssist.Hint>
</TextBox>
<Button
Grid.Column="1"
Margin="10,0"
Click="Cat_OnClick"
Content="+"
Resources="{StaticResource Material}"
ToolTip="Icon" />
</Grid>
<Grid Margin="0,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Command="{Binding ChangeBackGroundCommand}"
Resources="{StaticResource Material}"
ToolTip="Change BackGround">
<Button.Content>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<TextBlock Text="Change BackGround" />
<materialDesign:PackIcon
Margin="10,2,10,0"
VerticalAlignment="Center"
Kind="Wallpaper" />
</StackPanel>
</Button.Content>
</Button>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Margin="0,15,8,15"
Command="{Binding ResetDbCommand}"
Resources="{StaticResource Material}"
ToolTip="MaterialDesignIconButton">
<Button.Content>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<TextBlock Text="Reset Db" />
<materialDesign:PackIcon
Margin="10,4,10,0"
VerticalAlignment="Center"
Kind="DatabaseRemove" />
</StackPanel>
</Button.Content>
</Button>
<Button
Grid.Column="1"
Margin="8,15,0,15"
Command="{Binding ResetFolderCommand}"
Resources="{StaticResource Material}"
ToolTip="MaterialDesignIconButton">
<Button.Content>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<TextBlock Text="Reset Folder" />
<materialDesign:PackIcon
Margin="10,4,10,0"
VerticalAlignment="Center"
Kind="Folder" />
</StackPanel>
</Button.Content>
</Button>
</Grid>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,34 @@
using System.Windows;
using System.Windows.Controls;
using PlixP.ViewModels;
namespace PlixP.Views
{
/// <summary>
/// Interaction logic for MasterDetail
/// </summary>
public partial class MasterDetail : UserControl
{
public MasterDetail()
{
InitializeComponent();
}
private void Path_OnClick(object sender, RoutedEventArgs e)
{
(DataContext as MasterDetailViewModel)?.PathCommand.Execute(addPathTextBox.Text);
}
private void Cat_OnClick(object sender, RoutedEventArgs e)
{
(DataContext as MasterDetailViewModel)?.AddCategoryCommand.Execute(addCategoryTextBox.Text);
}
private void RemovePathButtonBase_OnClick(object sender, RoutedEventArgs e)
{
if(sender is Button button && button.DataContext is string str && DataContext is MasterDetailViewModel viewModel)
viewModel.RemovePathCommand.Execute(str);
}
}
}

View File

@ -0,0 +1,198 @@
<UserControl
x:Class="PlixP.Views.MovieList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
xmlns:renders="clr-namespace:PlixP.Renders"
xmlns:template="clr-namespace:PlixP.Views.Template"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<Grid Margin="10,25,10,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid
Grid.Row="0"
Height="90"
Margin="-15,-22"
Background="#40000000">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Margin="120,0,15,8" Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
FontSize="35"
FontWeight="Thin"
Text="">
<TextBlock Text="Movies" />
<TextBlock
Margin="0,5,0,0"
VerticalAlignment="Center"
FontSize="45"
FontWeight="Black"
Foreground="{StaticResource PrimaryBrush}"
Text="{Binding MovieListModel.MoviesCount}" />
<TextBlock Text="::" />
</TextBlock>
</StackPanel>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!--<Grid
Grid.Column="0"
Height="90"
Margin="10,0,30,0"
VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
<hc:CheckComboBox
Grid.Column="0"
VerticalAlignment="Center"
hc:InfoElement.Placeholder="Category"
DisplayMemberPath="Name"
ItemsSource="{Binding MovieListModel.OriginalCategories}"
ShowClearButton="True"
ShowSelectAllButton="True"
Style="{StaticResource CheckComboBoxPlus}" />
<hc:CheckComboBox
Grid.Column="1"
Margin="5,0"
VerticalAlignment="Center"
hc:InfoElement.Placeholder="Genre"
ItemsSource="{Binding MovieListModel.Genres}"
SelectionChanged="GenreSelector_OnSelectionChanged"
ShowClearButton="True"
ShowSelectAllButton="True"
Style="{StaticResource CheckComboBoxPlus}" />
</Grid>-->
<StackPanel
Grid.Column="1"
Margin="0,6,0,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<RadioButton
Margin="4"
hc:IconElement.Geometry="{StaticResource DownloadGeometry}"
Background="{DynamicResource SecondaryRegionBrush}"
Checked="AllToggleButton_OnChecked"
Content="ByAdded"
IsChecked="{Binding IsAllActive}"
Style="{StaticResource RadioButtonIcon}" />
<RadioButton
Margin="4"
hc:IconElement.Geometry="{StaticResource CalendarGeometry}"
Background="{DynamicResource SecondaryRegionBrush}"
Checked="ByReleaseToggleButton_OnChecked"
Content="ByRelease"
Style="{StaticResource RadioButtonIcon}" />
<RadioButton
Margin="4"
hc:IconElement.Geometry="{StaticResource StarGeometry}"
Background="{DynamicResource SecondaryRegionBrush}"
BorderThickness="1"
Checked="ByImdbRatingToggleButton_OnChecked"
Content="ByImdbRating"
Style="{StaticResource RadioButtonIcon}" />
<Button
Margin="5"
hc:IconElement.Geometry="{StaticResource InfoGeometry}"
Background="{DynamicResource SecondaryRegionBrush}"
Command="{Binding GenreSelectedCommand}"
Content="GENREs"
Style="{StaticResource ButtonPrimary}" />
</StackPanel>
</Grid>
<StackPanel
Grid.Column="3"
Margin="10,0,30,4"
Orientation="Horizontal">
<Button
Padding="6,7,0,0"
Command="{Binding RefreshCommand}"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
ToolTip="Refresh Movies">
<materialDesign:PackIcon Kind="Refresh" />
</Button>
<Button
Margin="10,0,0,0"
Padding="8,3,0,0"
Command="{Binding RefreshFilesCommand}"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
ToolTip="Refresh Files">
<materialDesign:PackIcon Kind="FileImport" />
</Button>
</StackPanel>
<TextBox
Name="searchTextBox"
Grid.Column="4"
MinWidth="300"
Margin="10,0,30,4"
VerticalAlignment="Center"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingHintTextBox}">
<materialDesign:HintAssist.Hint>
<StackPanel Margin="-2,0,0,0" Orientation="Horizontal">
<materialDesign:PackIcon Kind="Search" />
<TextBlock>
Seach
</TextBlock>
</StackPanel>
</materialDesign:HintAssist.Hint>
</TextBox>
<Button
Grid.Column="5"
Margin="15,0,50,0"
Padding="5,3,0,0"
VerticalAlignment="Center"
Click="SearchButtonBase_OnClick"
Content="{materialDesign:PackIcon Search}"
Resources="{StaticResource Material}"
Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
ToolTip="Icon" />
</Grid>
<ScrollViewer
Grid.Row="2"
Margin="0,25,0,4"
ScrollChanged="ScrollViewer_OnScrollChanged">
<ItemsControl
x:Name="moviesItemControl"
HorizontalAlignment="Center"
ItemsSource="{Binding Path=MovieListModel.PageMovies}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<template:MovieItem Margin="8,5" MouseDown="MovieItem_OnMouseDown" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
</UserControl>

View File

@ -0,0 +1,98 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using HandyControl.Controls;
using PlixP.Models;
using PlixP.ViewModels;
using PlixP.Views.Template;
using Prism.Regions;
using MessageBox = HandyControl.Controls.MessageBox;
using ScrollViewer = System.Windows.Controls.ScrollViewer;
namespace PlixP.Views
{
/// <summary>
/// Interaction logic for MovieList
/// </summary>
public partial class MovieList : UserControl
{
public ObservableCollection<Movie> Movies = new ObservableCollection<Movie>();
public MovieList(IRegionManager regionManager)
{
InitializeComponent();
regionManager.RegisterViewWithRegion("SuggestiontRegion", typeof(SuggestionBox));
}
private void MovieItem_OnMouseDown(object sender, MouseButtonEventArgs e)
{
(DataContext as MovieListViewModel)?.MovieSelectedCommand.Execute((sender as MovieItem).DataContext as Movie);
}
private void ScrollViewer_OnScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (DataContext is MovieListViewModel viewModel && sender is ScrollViewer scrollViewer && scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
{
viewModel.NextPageCommand.Execute(null);
}
}
private void AllToggleButton_OnChecked(object sender, RoutedEventArgs e)
{
if (sender is RadioButton button && DataContext is MovieListViewModel viewModel)
{
if(button.IsChecked.Value==true)
viewModel.CheckByAddedCommand.Execute(null);
}
}
private void ByReleaseToggleButton_OnChecked(object sender, RoutedEventArgs e)
{
if (sender is RadioButton button && DataContext is MovieListViewModel viewModel)
{
if (button.IsChecked.Value == true)
viewModel.CheckByRealease.Execute(null);
}
}
private void SearchButtonBase_OnClick(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(searchTextBox.Text))
{
MessageBox.Show("Please Enter Movie Name");
return;
}
if(DataContext is MovieListViewModel viewModel)
viewModel.SearchCommand.Execute(searchTextBox.Text);
}
private void ByImdbRatingToggleButton_OnChecked(object sender, RoutedEventArgs e)
{
if (sender is RadioButton button && DataContext is MovieListViewModel viewModel)
{
if (button.IsChecked.Value == true)
viewModel.CheckByImdbCommand.Execute(null);
}
}
private void GenreSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(sender is CheckComboBox comboBox && comboBox.SelectedItems is IList items && DataContext is MovieListViewModel viewModel)
{
var genres = new List<string>();
for (var i = 0; i < items.Count; i++)
{
if(items[0] is string str)
genres.Add(str);
}
viewModel.GenreSelectedCommand.Execute(genres);
}
}
}
}

View File

@ -0,0 +1,115 @@
<UserControl
x:Class="PlixP.Views.Template.MovieItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
xmlns:renders="clr-namespace:PlixP.Renders"
prism:ViewModelLocator.AutoWireViewModel="True">
<materialDesign:Card
Width="190"
Height="280"
Margin="12,8"
materialDesign:ShadowAssist.ShadowDepth="Depth4"
Background="#95222222"
MouseEnter="Item_OnMouseEnter"
MouseLeave="Item_OnMouseLeave"
UniformCornerRadius="10">
<Grid>
<renders:ImageCacher ImageSource="{Binding Poster}" Stretch="Fill" />
<Grid Background="#85000000" Visibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="1"
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="17"
FontWeight="Bold"
Text="{Binding Title}"
TextAlignment="Center"
TextWrapping="Wrap" />
<Grid Grid.Row="2" HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<hc:Shield
Status="{Binding Path=imdbRating}"
Subject="IMDB"
Color="#f39c12" />
<hc:Shield
Grid.Column="1"
Margin="5,0"
Status="{Binding Path=Quality}"
Subject="Quality"
Color="#2980b9" />
</Grid>
<TextBlock
Grid.Row="3"
Height="90"
Margin="8"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
FontSize="12"
FontWeight="Medium"
Text="{Binding Plot}"
TextAlignment="Justify"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
</Grid>
<Grid VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Margin="6" Orientation="Horizontal">
<materialDesign:Card
Padding="0"
materialDesign:ShadowAssist.ShadowDepth="Depth0"
Background="LightSteelBlue"
FontWeight="Black"
Opacity="0.9"
UniformCornerRadius="8"
Visibility="Visible">
<TextBlock
Margin="10,6"
Foreground="#444"
Text="{Binding Year}" />
</materialDesign:Card>
<materialDesign:Card
Name="dubbedCard"
Margin="2,0,0,0"
Padding="0"
materialDesign:ShadowAssist.ShadowDepth="Depth0"
Background="{StaticResource PrimaryBrush}"
FontWeight="Black"
Opacity="0.9"
UniformCornerRadius="8"
Visibility="Hidden">
<TextBlock
Margin="10,6"
Foreground="#444"
Text="Dubbed" />
</materialDesign:Card>
</StackPanel>
<Ellipse
Grid.Column="1"
Width="10"
Height="10"
Margin="5,0"
HorizontalAlignment="Right"
Fill="{Binding SeenStatusColor}" />
</Grid>
</Grid>
</materialDesign:Card>
</UserControl>

View File

@ -0,0 +1,51 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using MaterialDesignThemes.Wpf;
using PlixP.Models;
namespace PlixP.Views.Template
{
/// <summary>
/// Interaction logic for MovieItem
/// </summary>
public partial class MovieItem : UserControl
{
public MovieItem()
{
InitializeComponent();
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (e.Property == DataContextProperty)
{
if (DataContext is Movie)
{
if ((DataContext as Movie).IsDubbed)
dubbedCard.Visibility = Visibility.Visible;
else
dubbedCard.Visibility = Visibility.Hidden;
}
}
base.OnPropertyChanged(e);
}
private void Item_OnMouseEnter(object sender, MouseEventArgs e)
{
var card = sender as Card;
var grid = card.Content as Grid;
var mGrid = grid.Children[1] as Grid;
mGrid.Visibility = Visibility.Visible;
}
private void Item_OnMouseLeave(object sender, MouseEventArgs e)
{
var card = sender as Card;
var grid = card.Content as Grid;
var mGrid = grid.Children[1] as Grid;
mGrid.Visibility = Visibility.Hidden;
}
}
}

View File

@ -0,0 +1,21 @@
<UserControl
x:Class="PlixP.Views.Template.SuggestionBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
xmlns:renders="clr-namespace:PlixP.Renders"
xmlns:template="clr-namespace:PlixP.Views.Template"
xmlns:views="clr-namespace:PlixP.Views"
prism:ViewModelLocator.AutoWireViewModel="True"
TextElement.FontSize="13"
TextElement.FontWeight="Regular"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto">
<Grid Height="180">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</UserControl>

View File

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace PlixP.Views.Template
{
/// <summary>
/// Interaction logic for SuggestionBox
/// </summary>
public partial class SuggestionBox : UserControl
{
public SuggestionBox()
{
InitializeComponent();
}
}
}