mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-01-09 06:18:20 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a15139aa6 |
@@ -317,6 +317,13 @@
|
||||
</label>
|
||||
<div>
|
||||
<div class="field-input">
|
||||
<!-- Mobile-friendly autocomplete -->
|
||||
<app-mobile-autocomplete
|
||||
formControlName="unlinkedCategories"
|
||||
placeholder="Add category"
|
||||
></app-mobile-autocomplete>
|
||||
|
||||
<!-- Desktop autocomplete -->
|
||||
<p-autocomplete
|
||||
formControlName="unlinkedCategories"
|
||||
multiple
|
||||
@@ -325,6 +332,7 @@
|
||||
[suggestions]="unlinkedCategoriesSuggestions"
|
||||
(completeMethod)="onUnlinkedCategoriesComplete($event)"
|
||||
placeholder="Add category and press Enter"
|
||||
class="desktop-only"
|
||||
>
|
||||
</p-autocomplete>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
createDefaultCategory
|
||||
} from "../../shared/models/download-cleaner-config.model";
|
||||
import { ScheduleUnit, ScheduleOptions } from "../../shared/models/queue-cleaner-config.model";
|
||||
import { MobileAutocompleteComponent } from "../../shared/components/mobile-autocomplete/mobile-autocomplete.component";
|
||||
|
||||
// PrimeNG Components
|
||||
import { CardModule } from "primeng/card";
|
||||
@@ -54,7 +55,8 @@ import { DocumentationService } from "../../core/services/documentation.service"
|
||||
TableModule,
|
||||
LoadingErrorStateComponent,
|
||||
ConfirmDialogModule,
|
||||
NgIf
|
||||
NgIf,
|
||||
MobileAutocompleteComponent,
|
||||
],
|
||||
providers: [ConfirmationService],
|
||||
templateUrl: "./download-cleaner-settings.component.html",
|
||||
|
||||
@@ -191,6 +191,13 @@
|
||||
Ignored Downloads
|
||||
</label>
|
||||
<div class="field-input">
|
||||
<!-- Mobile-friendly autocomplete -->
|
||||
<app-mobile-autocomplete
|
||||
formControlName="ignoredDownloads"
|
||||
placeholder="Add download pattern"
|
||||
></app-mobile-autocomplete>
|
||||
|
||||
<!-- Desktop autocomplete -->
|
||||
<p-autocomplete
|
||||
formControlName="ignoredDownloads"
|
||||
inputId="ignoredDownloads"
|
||||
@@ -198,6 +205,7 @@
|
||||
fluid
|
||||
[typeahead]="false"
|
||||
placeholder="Add download pattern and press enter"
|
||||
class="desktop-only"
|
||||
></p-autocomplete>
|
||||
<small class="form-helper-text">Downloads matching these patterns will be ignored (e.g. hash, tag, category, label, tracker)</small>
|
||||
</div>
|
||||
|
||||
@@ -19,10 +19,12 @@ import { NotificationService } from '../../core/services/notification.service';
|
||||
import { DocumentationService } from '../../core/services/documentation.service';
|
||||
import { SelectModule } from "primeng/select";
|
||||
import { ChipsModule } from "primeng/chips";
|
||||
import { ChipModule } from "primeng/chip";
|
||||
import { AutoCompleteModule } from "primeng/autocomplete";
|
||||
import { LoadingErrorStateComponent } from "../../shared/components/loading-error-state/loading-error-state.component";
|
||||
import { ConfirmDialogModule } from "primeng/confirmdialog";
|
||||
import { ConfirmationService } from "primeng/api";
|
||||
import { MobileAutocompleteComponent } from "../../shared/components/mobile-autocomplete/mobile-autocomplete.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-general-settings",
|
||||
@@ -36,11 +38,13 @@ import { ConfirmationService } from "primeng/api";
|
||||
ButtonModule,
|
||||
InputNumberModule,
|
||||
ChipsModule,
|
||||
ChipModule,
|
||||
ToastModule,
|
||||
SelectModule,
|
||||
AutoCompleteModule,
|
||||
LoadingErrorStateComponent,
|
||||
ConfirmDialogModule,
|
||||
MobileAutocompleteComponent,
|
||||
],
|
||||
providers: [GeneralConfigStore, ConfirmationService],
|
||||
templateUrl: "./general-settings.component.html",
|
||||
|
||||
@@ -184,12 +184,20 @@
|
||||
Ignored Patterns
|
||||
</label>
|
||||
<div class="field-input">
|
||||
<!-- Mobile-friendly autocomplete -->
|
||||
<app-mobile-autocomplete
|
||||
formControlName="ignoredPatterns"
|
||||
placeholder="Add pattern"
|
||||
></app-mobile-autocomplete>
|
||||
|
||||
<!-- Desktop autocomplete -->
|
||||
<p-autocomplete
|
||||
formControlName="ignoredPatterns"
|
||||
multiple
|
||||
fluid
|
||||
[typeahead]="false"
|
||||
placeholder="Add pattern and press Enter"
|
||||
class="desktop-only"
|
||||
>
|
||||
</p-autocomplete>
|
||||
<small class="form-helper-text"
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
} from "../../shared/models/queue-cleaner-config.model";
|
||||
import { SettingsCardComponent } from "../components/settings-card/settings-card.component";
|
||||
import { ByteSizeInputComponent } from "../../shared/components/byte-size-input/byte-size-input.component";
|
||||
import { MobileAutocompleteComponent } from "../../shared/components/mobile-autocomplete/mobile-autocomplete.component";
|
||||
|
||||
// PrimeNG Components
|
||||
import { CardModule } from "primeng/card";
|
||||
@@ -54,6 +55,7 @@ import { ErrorHandlerUtil } from "../../core/utils/error-handler.util";
|
||||
AutoCompleteModule,
|
||||
DropdownModule,
|
||||
LoadingErrorStateComponent,
|
||||
MobileAutocompleteComponent,
|
||||
],
|
||||
providers: [QueueCleanerConfigStore],
|
||||
templateUrl: "./queue-cleaner-settings.component.html",
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
@media (max-width: 768px) {
|
||||
.desktop-only {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Documentation info icon styles
|
||||
.field-info-icon {
|
||||
margin-right: 0.5rem;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Mobile-friendly autocomplete styles */
|
||||
.mobile-autocomplete-container {
|
||||
.input-with-button {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.mobile-input {
|
||||
flex: 1;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.add-button {
|
||||
flex-shrink: 0;
|
||||
min-width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.chips-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive design - show mobile component on mobile devices */
|
||||
@media (max-width: 768px) {
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide mobile component on larger screens */
|
||||
@media (min-width: 769px) {
|
||||
:host {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { Component, Input, Output, EventEmitter, forwardRef } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { ChipModule } from 'primeng/chip';
|
||||
|
||||
@Component({
|
||||
selector: 'app-mobile-autocomplete',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
InputTextModule,
|
||||
ButtonModule,
|
||||
ChipModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => MobileAutocompleteComponent),
|
||||
multi: true
|
||||
}
|
||||
],
|
||||
template: `
|
||||
<div class="mobile-autocomplete-container">
|
||||
<div class="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
pInputText
|
||||
#inputField
|
||||
[placeholder]="placeholder"
|
||||
(keyup.enter)="addItem(inputField.value); inputField.value = ''"
|
||||
class="mobile-input"
|
||||
/>
|
||||
<button
|
||||
pButton
|
||||
type="button"
|
||||
icon="pi pi-plus"
|
||||
class="p-button-sm add-button"
|
||||
(click)="addItem(inputField.value); inputField.value = ''"
|
||||
[title]="'Add ' + placeholder"
|
||||
></button>
|
||||
</div>
|
||||
<div class="chips-container" *ngIf="value && value.length > 0">
|
||||
<p-chip
|
||||
*ngFor="let item of value; let i = index"
|
||||
[label]="item"
|
||||
[removable]="true"
|
||||
(onRemove)="removeItem(i)"
|
||||
class="mb-2 mr-2"
|
||||
></p-chip>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styleUrls: ['./mobile-autocomplete.component.scss']
|
||||
})
|
||||
export class MobileAutocompleteComponent implements ControlValueAccessor {
|
||||
@Input() placeholder: string = 'Add item and press Enter';
|
||||
@Input() multiple: boolean = true;
|
||||
|
||||
value: string[] = [];
|
||||
disabled: boolean = false;
|
||||
|
||||
// ControlValueAccessor implementation
|
||||
private onChange = (value: string[]) => {};
|
||||
private onTouched = () => {};
|
||||
|
||||
writeValue(value: string[]): void {
|
||||
this.value = value || [];
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: any): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled;
|
||||
}
|
||||
|
||||
addItem(item: string): void {
|
||||
if (item && item.trim() && !this.disabled) {
|
||||
const trimmedItem = item.trim();
|
||||
|
||||
// Check if item already exists
|
||||
if (!this.value.includes(trimmedItem)) {
|
||||
const newValue = [...this.value, trimmedItem];
|
||||
this.value = newValue;
|
||||
this.onChange(this.value);
|
||||
this.onTouched();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeItem(index: number): void {
|
||||
if (!this.disabled) {
|
||||
const newValue = this.value.filter((_, i) => i !== index);
|
||||
this.value = newValue;
|
||||
this.onChange(this.value);
|
||||
this.onTouched();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user