diff --git a/mediarepo-ui/src-tauri/Cargo.lock b/mediarepo-ui/src-tauri/Cargo.lock index 0d1e8d8..edc739a 100644 --- a/mediarepo-ui/src-tauri/Cargo.lock +++ b/mediarepo-ui/src-tauri/Cargo.lock @@ -1580,12 +1580,13 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mediarepo-api" -version = "0.5.1" -source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=b6a287e200eeae1105466ae7851a3a9287efe34b#b6a287e200eeae1105466ae7851a3a9287efe34b" +version = "0.6.0" +source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=ddebf4bf0c3e96ede64182ff52bd84f134acc33a#ddebf4bf0c3e96ede64182ff52bd84f134acc33a" dependencies = [ "async-trait", "chrono", "directories", + "mime_guess", "parking_lot", "rmp-ipc", "serde", @@ -1613,6 +1614,22 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minisign-verify" version = "0.1.8" @@ -2507,9 +2524,9 @@ dependencies = [ [[package]] name = "rmp-ipc" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e9a9202fb951b3ca3088a4edd351774ef154efabb759d6aac2911cc1ae60c1" +checksum = "87d2b669d0332e1478b88fdecf4c03cc0c8ce1d977a79eba848f4532213567e6" dependencies = [ "async-trait", "byteorder", @@ -3388,6 +3405,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.7" diff --git a/mediarepo-ui/src-tauri/Cargo.toml b/mediarepo-ui/src-tauri/Cargo.toml index efdf95f..c7422e6 100644 --- a/mediarepo-ui/src-tauri/Cargo.toml +++ b/mediarepo-ui/src-tauri/Cargo.toml @@ -30,7 +30,7 @@ features = ["env-filter"] [dependencies.mediarepo-api] git = "https://github.com/Trivernis/mediarepo-api.git" -rev = "b6a287e200eeae1105466ae7851a3a9287efe34b" +rev = "ddebf4bf0c3e96ede64182ff52bd84f134acc33a" features = ["tauri-plugin"] [features] diff --git a/mediarepo-ui/src/app/app.module.ts b/mediarepo-ui/src/app/app.module.ts index f443a4e..d8956b4 100644 --- a/mediarepo-ui/src/app/app.module.ts +++ b/mediarepo-ui/src/app/app.module.ts @@ -49,6 +49,11 @@ import {FilesTabSidebarComponent} from './pages/home/files-tab/files-tab-sidebar import {MatExpansionModule} from "@angular/material/expansion"; import {TagItemComponent} from './components/tag-item/tag-item.component'; import { FileEditComponent } from './components/file-edit/file-edit.component'; +import { ImportTabComponent } from './pages/home/import-tab/import-tab.component'; +import { ImportTabSidebarComponent } from './pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component'; +import { NativeFileSelectComponent } from './components/inputs/native-file-select/native-file-select.component'; +import { FilesystemImportComponent } from './pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component'; +import {MatCheckboxModule} from "@angular/material/checkbox"; @NgModule({ declarations: [ @@ -69,42 +74,47 @@ import { FileEditComponent } from './components/file-edit/file-edit.component'; FilesTabSidebarComponent, TagItemComponent, FileEditComponent, + ImportTabComponent, + ImportTabSidebarComponent, + NativeFileSelectComponent, + FilesystemImportComponent, ], - imports: [ - BrowserModule, - AppRoutingModule, - BrowserAnimationsModule, - MatCardModule, - MatListModule, - MatButtonModule, - MatToolbarModule, - MatSnackBarModule, - MatFormFieldModule, - MatInputModule, - ReactiveFormsModule, - MatSidenavModule, - MatGridListModule, - MatProgressBarModule, - MatPaginatorModule, - ScrollingModule, - MatChipsModule, - MatIconModule, - MatAutocompleteModule, - MatTabsModule, - FlexModule, - GridModule, - MatRippleModule, - MatDialogModule, - MatSelectModule, - MatProgressSpinnerModule, - BlockUIModule, - PanelModule, - DragDropModule, - MatSliderModule, - MatTooltipModule, - MatMenuModule, - MatExpansionModule, - ], + imports: [ + BrowserModule, + AppRoutingModule, + BrowserAnimationsModule, + MatCardModule, + MatListModule, + MatButtonModule, + MatToolbarModule, + MatSnackBarModule, + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + MatSidenavModule, + MatGridListModule, + MatProgressBarModule, + MatPaginatorModule, + ScrollingModule, + MatChipsModule, + MatIconModule, + MatAutocompleteModule, + MatTabsModule, + FlexModule, + GridModule, + MatRippleModule, + MatDialogModule, + MatSelectModule, + MatProgressSpinnerModule, + BlockUIModule, + PanelModule, + DragDropModule, + MatSliderModule, + MatTooltipModule, + MatMenuModule, + MatExpansionModule, + MatCheckboxModule, + ], providers: [], bootstrap: [AppComponent] }) diff --git a/mediarepo-ui/src/app/components/file-gallery/file-gallery.component.ts b/mediarepo-ui/src/app/components/file-gallery/file-gallery.component.ts index 9e9c680..d924fe1 100644 --- a/mediarepo-ui/src/app/components/file-gallery/file-gallery.component.ts +++ b/mediarepo-ui/src/app/components/file-gallery/file-gallery.component.ts @@ -16,6 +16,7 @@ import {SafeResourceUrl} from "@angular/platform-browser"; import {Selectable} from "../../models/Selectable"; import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling"; import {CdkDragMove} from "@angular/cdk/drag-drop"; +import {TabService} from "../../services/tab/tab.service"; @Component({ selector: 'app-file-gallery', @@ -42,7 +43,8 @@ export class FileGalleryComponent implements OnChanges, OnInit { public imagePosition = {x: 0, y: 0}; public mouseInImageView = false; - constructor(private fileService: FileService) { + constructor(private tabService: TabService, private fileService: FileService) { + tabService.selectedTab.subscribe(() => this.adjustElementSizes()); } /** @@ -56,25 +58,31 @@ export class FileGalleryComponent implements OnChanges, OnInit { this.selectedFile?.unselect(); entry.select(); this.selectedFile = entry; - const selectedIndex = this.entries.indexOf(entry); - //this.virtualScroll.scrollToIndex(, "smooth"); await this.loadSelectedFile(); if (this.virtualScroll) { - const viewportSize = this.virtualScroll.getViewportSize(); - const indexAdjustment = (viewportSize / 260) / 2; // adjustment to have the selected item centered - this.virtualScroll.scrollToIndex( - Math.max(selectedIndex - indexAdjustment, 0), "smooth"); - - if (selectedIndex > indexAdjustment) { - this.virtualScroll.scrollToOffset( - this.virtualScroll.measureScrollOffset("left") + 130, "smooth"); - } + this.scrollToSelection(); } + this.fileSelectEvent.emit(this.selectedFile.data); } } + private scrollToSelection(): void { + if (this.selectedFile) { + const selectedIndex = this.entries.indexOf(this.selectedFile); + const viewportSize = this.virtualScroll.getViewportSize(); + const indexAdjustment = (viewportSize / 260) / 2; // adjustment to have the selected item centered + this.virtualScroll.scrollToIndex( + Math.max(selectedIndex - indexAdjustment, 0), "smooth"); + + if (selectedIndex > indexAdjustment) { + this.virtualScroll.scrollToOffset( + this.virtualScroll.measureScrollOffset("left") + 130, "smooth"); + } + } + } + /** * Loads the content url of the selected file * @returns {Promise} @@ -192,4 +200,11 @@ export class FileGalleryComponent implements OnChanges, OnInit { } return undefined; } + + public adjustElementSizes(): void { + if (this.virtualScroll) { + this.virtualScroll.checkViewportSize(); + this.scrollToSelection(); + } + } } diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid.component.ts b/mediarepo-ui/src/app/components/file-grid/file-grid.component.ts index 004aa91..3e2e606 100644 --- a/mediarepo-ui/src/app/components/file-grid/file-grid.component.ts +++ b/mediarepo-ui/src/app/components/file-grid/file-grid.component.ts @@ -14,6 +14,7 @@ import {File} from "../../models/File"; import {FileGridEntryComponent} from "./file-grid-entry/file-grid-entry.component"; import {GridEntry} from "./file-grid-entry/GridEntry"; import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling"; +import {TabService} from "../../services/tab/tab.service"; @Component({ selector: 'app-file-grid', @@ -38,7 +39,8 @@ export class FileGridComponent implements OnChanges, OnInit { private ctrlClicked = false; private gridEntries: GridEntry[] = [] - constructor() { + constructor(private tabService: TabService) { + tabService.selectedTab.subscribe(() => this.adjustElementSizes()); } public ngOnInit(): void { @@ -181,4 +183,10 @@ export class FileGridComponent implements OnChanges, OnInit { break; } } + + public adjustElementSizes(): void { + if (this.virtualScroll) { + this.virtualScroll.checkViewportSize(); + } + } } diff --git a/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.html b/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.html new file mode 100644 index 0000000..5861d6d --- /dev/null +++ b/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.html @@ -0,0 +1,17 @@ +
+ + + {{label}} + + +
+ + +
+ +
+
diff --git a/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.scss b/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.scss new file mode 100644 index 0000000..10d05c5 --- /dev/null +++ b/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.scss @@ -0,0 +1,22 @@ +.file-select-inner, mat-form-field { + width: 100%; +} + + +.file-input { + width: calc(100% - 3em); + float: left; + text-overflow: ellipsis; +} + +.buttons-native-select { + position: absolute; + top: 0; + right: 0; + margin-top: -19px; + + button { + width: 3em; + height: 3em; + } +} diff --git a/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.spec.ts b/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.spec.ts new file mode 100644 index 0000000..6800d85 --- /dev/null +++ b/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NativeFileSelectComponent } from './native-file-select.component'; + +describe('NativeFileSelectComponent', () => { + let component: NativeFileSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ NativeFileSelectComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NativeFileSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.ts b/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.ts new file mode 100644 index 0000000..852ea45 --- /dev/null +++ b/mediarepo-ui/src/app/components/inputs/native-file-select/native-file-select.component.ts @@ -0,0 +1,83 @@ +import { + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges +} from '@angular/core'; +import {FormControl} from "@angular/forms"; +import {dialog} from "@tauri-apps/api"; +import {DialogFilter} from "@tauri-apps/api/dialog"; + +@Component({ + selector: 'app-native-file-select', + templateUrl: './native-file-select.component.html', + styleUrls: ['./native-file-select.component.scss'] +}) +export class NativeFileSelectComponent implements OnInit, OnChanges { + + + @Input() mode: "files" | "folders" = "files"; + @Input() formControlName: string | undefined; + @Input() formControl: FormControl | undefined; + @Input() startPath: string | undefined; + @Input() multiSelect: boolean = true; + @Input() filters: DialogFilter[] = []; + + @Output() fileSelect = new EventEmitter(); + + public files: string[] = []; + public label: string | undefined; + + constructor() { + } + + public ngOnInit(): void { + this.setLabel(); + } + + + public ngOnChanges(changes: SimpleChanges): void { + if (changes["mode"]) { + this.setLabel(); + } + } + + public setFiles(filesExpr: string) { + this.files = filesExpr.split(","); + this.fileSelect.emit(this.files); + } + + /** + * Opens the native dialog to select files or folders + * @param {boolean} folders + * @returns {Promise} + */ + public async openNativeFileSelectDialog(folders: boolean) { + const files = await dialog.open({ + multiple: this.multiSelect, + directory: folders, + defaultPath: this.startPath, + filters: this.filters, + }); + if (files instanceof Array) { + this.files = files; + } else if (files) { + this.files = [files]; + } + this.fileSelect.emit(this.files); + } + + private setLabel(): void { + switch (this.mode) { + case "files": + this.label = "Select Files"; + break; + case "folders": + this.label = "Select a folder"; + break; + } + } +} diff --git a/mediarepo-ui/src/app/models/AddFileOptions.ts b/mediarepo-ui/src/app/models/AddFileOptions.ts new file mode 100644 index 0000000..120ac61 --- /dev/null +++ b/mediarepo-ui/src/app/models/AddFileOptions.ts @@ -0,0 +1,8 @@ +export class AddFileOptions { + public read_tags_from_txt = true; + public delete_after_import = false; + + constructor() { + } + +} diff --git a/mediarepo-ui/src/app/models/FileOsMetadata.ts b/mediarepo-ui/src/app/models/FileOsMetadata.ts new file mode 100644 index 0000000..c218b02 --- /dev/null +++ b/mediarepo-ui/src/app/models/FileOsMetadata.ts @@ -0,0 +1,7 @@ +export type FileOsMetadata = { + name: string, + path: string, + mime_type: string, + created_at: Date, + modified_at: Date, +} diff --git a/mediarepo-ui/src/app/pages/home/files-tab/files-tab.component.html b/mediarepo-ui/src/app/pages/home/files-tab/files-tab.component.html index 1f9293f..d10c740 100644 --- a/mediarepo-ui/src/app/pages/home/files-tab/files-tab.component.html +++ b/mediarepo-ui/src/app/pages/home/files-tab/files-tab.component.html @@ -1,4 +1,4 @@ - + - + + + + diff --git a/mediarepo-ui/src/app/pages/home/home.component.ts b/mediarepo-ui/src/app/pages/home/home.component.ts index ba60124..8d3bfc3 100644 --- a/mediarepo-ui/src/app/pages/home/home.component.ts +++ b/mediarepo-ui/src/app/pages/home/home.component.ts @@ -1,8 +1,9 @@ import {Component, OnInit, ViewChild} from '@angular/core'; import {Repository} from "../../models/Repository"; import {RepositoryService} from "../../services/repository/repository.service"; -import {MatTabGroup} from "@angular/material/tabs"; +import {MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs"; import {TagService} from "../../services/tag/tag.service"; +import {TabService} from "../../services/tab/tab.service"; @Component({ selector: 'app-home', @@ -16,8 +17,11 @@ export class HomeComponent implements OnInit { @ViewChild("tabGroup") tabGroup!: MatTabGroup; - constructor(private repoService: RepositoryService, private tagService: TagService) { - } + constructor( + private tabService: TabService, + private repoService: RepositoryService, + private tagService: TagService) + {} public async ngOnInit(): Promise { this.selectedRepository = this.repoService.selectedRepository.getValue(); @@ -42,4 +46,8 @@ export class HomeComponent implements OnInit { async loadRepoData() { await this.tagService.loadTags(); } + + public onTabSelectionChange(event: MatTabChangeEvent): void { + this.tabService.setSelectedTab(event.index); + } } diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.html b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.html new file mode 100644 index 0000000..a4e989f --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.html @@ -0,0 +1,30 @@ + + Selection Type + + Folders + Files + + + + + + + +
+ Import tags from + adjacent .txt tag files + + + Delete files from original location after import + +
+ + + + + diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.scss b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.scss new file mode 100644 index 0000000..5bba0b1 --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.scss @@ -0,0 +1,25 @@ +app-native-file-select { + width: 100%; +} + +button { + width: 100%; +} + +mat-divider { + width: 100%; + height: 1px; + margin: 1em 0; +} + +.filled-button { + background-color: #5c5c5c; +} + +.binary-import-options { + margin-top: 1em; + + mat-checkbox { + margin: 0.5em 0; + } +} diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.spec.ts b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.spec.ts new file mode 100644 index 0000000..6252f90 --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FilesystemImportComponent } from './filesystem-import.component'; + +describe('FilesystemImportComponent', () => { + let component: FilesystemImportComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ FilesystemImportComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(FilesystemImportComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.ts b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.ts new file mode 100644 index 0000000..09459b2 --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/filesystem-import/filesystem-import.component.ts @@ -0,0 +1,63 @@ +import {Component, EventEmitter, Output} from '@angular/core'; +import {FileOsMetadata} from "../../../../../models/FileOsMetadata"; +import {ImportService} from "../../../../../services/import/import.service"; +import {ErrorBrokerService} from "../../../../../services/error-broker/error-broker.service"; +import {AddFileOptions} from "../../../../../models/AddFileOptions"; +import {File} from "../../../../../models/File"; + +@Component({ + selector: 'app-filesystem-import', + templateUrl: './filesystem-import.component.html', + styleUrls: ['./filesystem-import.component.scss'] +}) +export class FilesystemImportComponent { + + @Output() fileImported = new EventEmitter(); + @Output() importFinished = new EventEmitter(); + + public fileCount: number = 0; + public files: FileOsMetadata[] = []; + public importOptions = new AddFileOptions(); + + public resolving = false; + public importing = false; + public importingProgress = 0; + + constructor(private errorBroker: ErrorBrokerService, private importService: ImportService) { + } + + public async setSelectedPaths(paths: string[]) { + this.resolving = true; + try { + this.files = await this.importService.resolvePathsToFiles(paths); + this.fileCount = this.files.length; + } catch (err) { + console.log(err); + this.errorBroker.showError(err); + } + this.resolving = false; + } + + public async import() { + this.importing = true; + + this.importingProgress = 0; + let count = 0; + + for (const file of this.files) { + try { + const resultFile = await this.importService.addLocalFile(file, + this.importOptions); + this.fileImported.emit(resultFile); + } catch (err) { + console.log(err); + this.errorBroker.showError(err); + } + count++; + this.importingProgress = (count / this.fileCount) * 100; + } + + this.importing = false; + this.importFinished.emit(); + } +} diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.html b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.html new file mode 100644 index 0000000..84de2f8 --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.html @@ -0,0 +1,20 @@ +
+ + +
+
+ + Import Type + + Filesystem + + + +
+
+ +
+
+
+
+
diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.scss b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.scss new file mode 100644 index 0000000..7a59d9d --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.scss @@ -0,0 +1,34 @@ +mat-tab-group, mat-tab { + width: 100%; + height: 100%; +} + + +.import-tab-inner { + display: block; + width: 100%; + height: 100%; + overflow: hidden; +} + +.import-type-select-wrapper { + width: 100%; + + .import-type-select { + width: calc(100% - 2em); + height: calc(100% - 2em); + margin: 1em; + mat-select { + height: 100%; + } + } +} + +.import-sidebar-tab-inner { + width: 100%; + height: 100%; +} + +.import-configuration { + padding: 1em; +} diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.spec.ts b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.spec.ts new file mode 100644 index 0000000..1a67b9f --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ImportTabSidebarComponent } from './import-tab-sidebar.component'; + +describe('ImportTabSidebarComponent', () => { + let component: ImportTabSidebarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ImportTabSidebarComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ImportTabSidebarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.ts b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.ts new file mode 100644 index 0000000..546476c --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab-sidebar/import-tab-sidebar.component.ts @@ -0,0 +1,22 @@ +import { + Component, + EventEmitter, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import {MatTabGroup} from "@angular/material/tabs"; +import {File} from "../../../../models/File"; + +@Component({ + selector: 'app-import-tab-sidebar', + templateUrl: './import-tab-sidebar.component.html', + styleUrls: ['./import-tab-sidebar.component.scss'] +}) +export class ImportTabSidebarComponent { + + @Output() fileImported = new EventEmitter(); + @Output() importFinished = new EventEmitter(); + + constructor() { } +} diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.html b/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.html new file mode 100644 index 0000000..2a918d3 --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.scss b/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.scss new file mode 100644 index 0000000..2fe967e --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.scss @@ -0,0 +1,27 @@ +mat-drawer-container { + height: 100%; + width: 100%; + margin: 0; + overflow: hidden; +} + +mat-drawer-content { + overflow-x: hidden; + overflow-y: auto; + height: 100%; +} + +mat-drawer { + height: 100%; + width: 25%; +} + +app-import-tab-sidebar, app-file-grid { + height: 100%; + width: 100%; + margin: 0; +} + +app-file-grid { + display: block; +} diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.spec.ts b/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.spec.ts new file mode 100644 index 0000000..10d3571 --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ImportTabComponent } from './import-tab.component'; + +describe('ImportTabComponent', () => { + let component: ImportTabComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ImportTabComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ImportTabComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.ts b/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.ts new file mode 100644 index 0000000..cf8980f --- /dev/null +++ b/mediarepo-ui/src/app/pages/home/import-tab/import-tab.component.ts @@ -0,0 +1,39 @@ +import {Component, ViewChild} from '@angular/core'; +import {File} from "../../../models/File"; +import {FileService} from "../../../services/file/file.service"; +import {FileGridComponent} from "../../../components/file-grid/file-grid.component"; + +@Component({ + selector: 'app-import-tab', + templateUrl: './import-tab.component.html', + styleUrls: ['./import-tab.component.scss'] +}) +export class ImportTabComponent { + + public files: File[] = []; + + @ViewChild("fileGrid") fileGrid!: FileGridComponent; + + constructor(private fileService: FileService) { + } + + /** + * Adds an imported file to the list of imported files + * @param {File} file + * @returns {Promise} + */ + public async addFileFromImport(file: File) { + this.files.push(file); + if (this.files.length % 50 === 0) { // refresh every 50 pictures + this.refreshFileView(); + } + } + + /** + * Refreshes the file view + * @returns {Promise} + */ + public refreshFileView() { + this.files = [...this.files]; + } +} diff --git a/mediarepo-ui/src/app/services/import/import.service.spec.ts b/mediarepo-ui/src/app/services/import/import.service.spec.ts new file mode 100644 index 0000000..da66864 --- /dev/null +++ b/mediarepo-ui/src/app/services/import/import.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ImportService } from './import.service'; + +describe('ImportService', () => { + let service: ImportService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ImportService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/services/import/import.service.ts b/mediarepo-ui/src/app/services/import/import.service.ts new file mode 100644 index 0000000..e0c18a2 --- /dev/null +++ b/mediarepo-ui/src/app/services/import/import.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; +import {FileOsMetadata} from "../../models/FileOsMetadata"; +import {invoke} from "@tauri-apps/api/tauri"; +import {AddFileOptions} from "../../models/AddFileOptions"; +import {File} from "../../models/File"; + +@Injectable({ + providedIn: 'root' +}) +export class ImportService { + + constructor() { } + + /** + * Resolves paths from the local file system into a list of files that can be imported + * @param {string[]} paths + * @returns {Promise} + */ + public async resolvePathsToFiles(paths: string[]): Promise { + return await invoke("plugin:mediarepo|resolve_paths_to_files", {paths}); + } + + /** + * Imports a file from the local file system + * @param {FileOsMetadata} metadata + * @param {AddFileOptions} options + * @returns {Promise} + */ + public async addLocalFile(metadata: FileOsMetadata, options: AddFileOptions): Promise { + return await invoke("plugin:mediarepo|add_local_file", {metadata, options}); + } +} diff --git a/mediarepo-ui/src/app/services/tab/tab.service.spec.ts b/mediarepo-ui/src/app/services/tab/tab.service.spec.ts new file mode 100644 index 0000000..6621cb9 --- /dev/null +++ b/mediarepo-ui/src/app/services/tab/tab.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { TabService } from './tab.service'; + +describe('TabService', () => { + let service: TabService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(TabService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/services/tab/tab.service.ts b/mediarepo-ui/src/app/services/tab/tab.service.ts new file mode 100644 index 0000000..d6bfcf6 --- /dev/null +++ b/mediarepo-ui/src/app/services/tab/tab.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import {BehaviorSubject} from "rxjs"; + +@Injectable({ + providedIn: 'root' +}) +export class TabService { + + public selectedTab = new BehaviorSubject(0); + constructor() { } + + public setSelectedTab(index: number) { + this.selectedTab.next(index); + } +}