Improved carousel (supports variable amount of slides to show at the same time). Fixed some config file issues

merge-notes
isark 2 years ago
parent 95a69df695
commit 2e3e4bb4ca

@ -1,9 +1,5 @@
use std::{
collections::HashMap,
path::{Path, PathBuf},
};
use std::collections::HashMap;
use poe_data::world_area::WorldArea;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
@ -36,7 +32,9 @@ struct OldArea {
}
pub fn convert_old(path: &str) -> Option<Plan> {
let plan: OldPlan = serde_json::from_str(&std::fs::read_to_string(path).expect("Could not convert old")).expect("could not convert old");
let plan: OldPlan =
serde_json::from_str(&std::fs::read_to_string(path).expect("Could not convert old"))
.expect("could not convert old");
let map = poe_data::world_area::load_world_areas_map(include_str!(
"../../data/processed_world_areas.json"
@ -47,10 +45,14 @@ pub fn convert_old(path: &str) -> Option<Plan> {
.collect::<HashMap<usize, &String>>();
Some(Plan {
current: 0,
plan: plan.elements.into_iter().map(|plan_element| PlanElement {
area_key: map[&plan_element.area._rid].to_owned(),
notes: plan_element.note,
}).collect::<Vec<PlanElement>>(),
current: plan.position,
plan: plan
.elements
.into_iter()
.map(|plan_element| PlanElement {
area_key: map[&plan_element.area._rid].to_owned(),
notes: plan_element.note,
})
.collect::<Vec<PlanElement>>(),
})
}

@ -22,8 +22,18 @@ fn proj_dir() -> Option<ProjectDirs> {
ProjectDirs::from(QUALIFIER, ORGANIZATION, APPLICATION)
}
fn mkdir() {
if let Some(proj_dir) = proj_dir() {
let dir_structure = proj_dir.data_dir().join(SAVED_PLANS);
std::fs::create_dir_all(dir_structure)
.map_err(|e| log::error!("Could not create directory for storing config and saves"))
.ok();
}
}
impl Default for Storage {
fn default() -> Self {
mkdir();
let storage = Self::load();
match storage {
Some(storage) => storage,
@ -38,7 +48,7 @@ impl Default for Storage {
impl Storage {
fn load() -> Option<Self> {
let storage: Option<Storage> = serde_json::from_str(
&std::fs::read_to_string(proj_dir()?.data_dir().with_file_name(CONFIG_FILE)).ok()?,
&std::fs::read_to_string(proj_dir()?.data_dir().join(CONFIG_FILE)).ok()?,
)
.ok();
@ -50,9 +60,9 @@ impl Storage {
pub fn save(&self) {
if let Ok(content) = serde_json::to_string_pretty(&self) {
if let Some(dir) = proj_dir() {
match std::fs::write(dir.data_dir().with_file_name(CONFIG_FILE), content) {
match std::fs::write(dir.data_dir().join(CONFIG_FILE), content) {
Ok(_) => {
if let Some(c) = dir.data_dir().with_file_name(CONFIG_FILE).to_str() {
if let Some(c) = dir.data_dir().join(CONFIG_FILE).to_str() {
log::info!("Saved config to {}", c)
}
}
@ -70,22 +80,11 @@ impl Storage {
if !path.ends_with(SAVED_PLANS) {
if let Some(proj_dir) = proj_dir() {
if let Some(file_name) = plan_file.file_name() {
let copy_result = std::fs::copy(
&file,
proj_dir
.data_dir()
.join(SAVED_PLANS)
.with_file_name(file_name),
);
let dest = proj_dir.data_dir().join(SAVED_PLANS).join(file_name);
let copy_result = std::fs::copy(&file, &dest);
match copy_result {
Ok(_) => {
file = proj_dir
.data_dir()
.join(SAVED_PLANS)
.with_file_name(file_name)
.to_str()
.unwrap()
.to_string()
file = dest.to_str()?.to_string();
}
Err(e) => log::error!("Could not store plan file {e:?}"),
}
@ -95,13 +94,19 @@ impl Storage {
}
log::info!("Loading plan: {file:?}");
if let Some(plan) = serde_json::from_str(&std::fs::read_to_string(&file).ok()?).ok()
{
if let Some(plan) = serde_json::from_str(&std::fs::read_to_string(&file).ok()?).ok() {
plan
} else {
log::info!("Attempting to convert old");
let plan = convert_old(&file)?;
std::fs::write(&file, serde_json::to_string(&plan).ok()?).ok();
std::fs::write(
&file,
serde_json::to_string(&plan)
.map_err(|e| log::error!("Could not serialize converted plan to json {e:?}"))
.ok()?,
)
.map_err(|e| "Could not write converted plan to storage")
.ok();
Some(plan)
}
}

@ -11,16 +11,16 @@
.slide {
background-color: green;
grid-template-rows: 1;
grid-row-start: 1;
}
.slide-vertical {
background-color: green;
grid-template-columns: 1;
grid-column-start: 1;
}
}
.window {
display: grid;
@ -28,16 +28,6 @@
height: 100%;
}
// .window {
// grid-template-columns: repeat(3, 1fr);
// grid-auto-flow: column;
// }
// .window-vertical {
// grid-template-rows: repeat(3, 1fr);
// grid-auto-flow: row;
// }
.current {
background-color: magenta;
}

@ -37,9 +37,7 @@ export class CarouselComponent implements OnInit, AfterViewInit {
@Output() changedIndex: EventEmitter<number> = new EventEmitter<number>();
@Input() slides?: any[];
@ContentChild(TemplateRef) template?: TemplateRef<any>;
@ViewChild('carouselWindow') window!: ElementRef;
@ViewChildren('slideElement') slideElements!: QueryList<ElementRef>;
current: number = 0;
@ -50,6 +48,7 @@ export class CarouselComponent implements OnInit, AfterViewInit {
angularAnimating: boolean = false;
animation: string = 'vertical';
directionTime: number = 0;
@Input() numVisible: number = 1;
private debouncedOnchange: Subject<void> = new Subject<void>();
@ -91,6 +90,14 @@ export class CarouselComponent implements OnInit, AfterViewInit {
}
numExtraNext() {
return Math.floor((this.numVisible - 1) / 2);
}
numExtraPrev() {
return Math.ceil((this.numVisible - 1) / 2);
}
ngAfterViewInit(): void {
this.slideElements.changes.subscribe((comps: QueryList<ElementRef>) => {
@ -104,16 +111,13 @@ export class CarouselComponent implements OnInit, AfterViewInit {
}
initialize() {
this.visibleSlides?.push({
index: 0,
hasBeenVisible: false,
currentlyIntersecting: false,
})
this.visibleSlides?.push({
index: 1,
hasBeenVisible: false,
currentlyIntersecting: false,
})
for(let i = 0; i <= this.numExtraNext() && i < this.slides!.length; i++) {
this.visibleSlides?.push({
index: i,
hasBeenVisible: false,
currentlyIntersecting: false,
})
}
}
handleNewDomSlide(ref: ElementRef) {
@ -125,11 +129,11 @@ export class CarouselComponent implements OnInit, AfterViewInit {
if (this.slides && this.current + 1 < this.slides?.length) {
this.current += 1;
this.changedIndex.emit(this.current);
if (this.current + 1 < this.slides.length) {
if (!this.visibleSlides?.find(e => e.index == this.current + 1)) {
console.log("numextra", this.numExtraNext());
if (this.current + this.numExtraNext() < this.slides.length) {
if (!this.visibleSlides?.find(e => e.index == this.current + this.numExtraNext() )) {
this.visibleSlides?.push({
index: this.current + 1,
index: this.current + this.numExtraNext(),
hasBeenVisible: false,
currentlyIntersecting: false,
});
@ -145,10 +149,10 @@ export class CarouselComponent implements OnInit, AfterViewInit {
this.current -= 1;
this.changedIndex.emit(this.current);
if (this.current - 1 >= 0) {
if (!this.visibleSlides?.find(e => e.index == this.current - 1)) {
if (this.current - this.numExtraPrev() >= 0) {
if (!this.visibleSlides?.find(e => e.index == this.current - this.numExtraPrev())) {
this.visibleSlides?.push({
index: this.current - 1,
index: this.current - this.numExtraPrev(),
hasBeenVisible: false,
currentlyIntersecting: false,
});
@ -163,22 +167,23 @@ export class CarouselComponent implements OnInit, AfterViewInit {
}
realOnChange() {
const safetyFactor = this.numVisible == 1 ? 1 : 2;
{
const intersecting = this.visibleSlides?.filter(e => e.currentlyIntersecting).sort((e1, e2) => e1.index - e2.index);
const lowestIntersecting = intersecting![0];
this.visibleSlides = this.visibleSlides?.filter(e => e.index + 2 >= lowestIntersecting!.index && e.index >= this.current - 2);
this.visibleSlides = this.visibleSlides?.filter(e => e.index + safetyFactor >= lowestIntersecting!.index && e.index >= this.current - this.numExtraPrev());
}
{
const intersecting = this.visibleSlides?.filter(e => e.currentlyIntersecting).sort((e1, e2) => e1.index - e2.index).reverse();
const highestIntersecting = intersecting![0]
this.visibleSlides = this.visibleSlides?.filter(e => e.index - 2 <= highestIntersecting!.index && e.index <= this.current + 2);
this.visibleSlides = this.visibleSlides?.filter(e => e.index - safetyFactor <= highestIntersecting!.index && e.index <= this.current + this.numExtraNext());
}
}
translation() {
let num = (this.current - 1) * (-1 / 3) * 100;
let num = (this.current - this.numExtraNext() - (this.numVisible % 2 == 0 ? 1 : 0)) * (-1 / this.numVisible) * 100;
if (this.vertical) {
return `0 ${num}%`
} else {
@ -189,7 +194,7 @@ export class CarouselComponent implements OnInit, AfterViewInit {
templateValue() {
const len = this.slides?.length;
return `repeat(${len}, minmax(calc(100% / 3), 1fr))`;
return `repeat(${len}, minmax(calc(100% / ${this.numVisible}), 1fr))`;
}
style() {

@ -4,26 +4,23 @@
#targetRef>
<ng-container *ngIf="plan">
<carousel [slides]="plan.elements" (afterInitSelf)="registerCarousel($event)" #caro>
<carousel [slides]="slides" (afterInitSelf)="registerZoneSlides($event)">
<ng-template let-slide>
{{slide}}
ZONE{{slide}}
</ng-template>
</carousel>
<carousel [slides]="slides" (afterInitSelf)="registerCurrentSlides($event)">
<ng-template let-slide>
CURRENT{{slide}}
</ng-template>
</carousel>
<div class="mainSlideContent">
<span class="notes-label">Notes:</span><span class="notes">{{plan.elements[slideIndex].note}}</span>
</div>
</ng-container>
</div>
<div *ngIf="carouselComponent" class="controls">
<button (click)="carouselComponent.prev()">&lt;=prev</button>
<button (click)="carouselComponent.next()">next&gt;</button>
<button (click)="carouselComponent.changeDirection()">toggle direction</button>
<div class="slidecontainer">
Direction change time: {{carouselComponent.directionTime}}<br>
<input type="range" min="0" max="1000" [(ngModel)]="carouselComponent.directionTime" class="slider" id="myRange">
</div>
<div *ngIf="currentSlides" class="controls">
<button (click)="prev()">&lt;=prev</button>
<button (click)="next()">next&gt;</button>
</div>
<ngx-moveable [target]="targetRef" [draggable]="draggable" [resizable]="true" (drag)="onDrag($event)"

@ -19,16 +19,17 @@ export class PlanDisplayComponent implements AfterViewInit, OnInit {
draggable: boolean = true;
rect?: Rect;
// slides!: number[];
slides: number[] = [];
plan?: Plan;
slideIndex: number = 0;
carouselComponent?: CarouselComponent;
zoneSlides?: CarouselComponent;
currentSlides?: CarouselComponent;
constructor(private configService: ConfigService, private cdr: ChangeDetectorRef, private shortcut: ShortcutService, private planService: PlanService) {
// for(let i = 0; i < 100; i++) {
// this.slides.push(i);
// }
for (let i = 0; i < 100; i++) {
this.slides.push(i);
}
}
ngOnInit() {
@ -92,16 +93,26 @@ export class PlanDisplayComponent implements AfterViewInit, OnInit {
}
}
registerCarousel(carousel: CarouselComponent) {
this.carouselComponent = carousel
if (this.carouselComponent) {
this.shortcut.register("F7", () => {
this.carouselComponent?.prev();
});
this.shortcut.register("F8", () => {
this.carouselComponent?.next();
});
} else {
registerZoneSlides(carousel: CarouselComponent) {
this.zoneSlides = carousel;
console.log("zone slides");
}
registerCurrentSlides(carousel: CarouselComponent) {
this.currentSlides = carousel;
if (this.currentSlides) {
this.shortcut.register("F7", this.prev.bind(this));
this.shortcut.register("F8", this.next.bind(this));
}
}
next() {
this.currentSlides?.next();
this.zoneSlides?.next();
}
prev() {
this.currentSlides?.prev();
this.zoneSlides?.prev();
}
}

@ -1,7 +1,6 @@
import { Injectable, NgZone } from '@angular/core';
import { ShortcutHandler, register, unregister } from '@tauri-apps/api/globalShortcut';
import { EMPTY, Observable, catchError, empty, from } from 'rxjs';
import { ConfigService } from './config.service';
import { EMPTY, from } from 'rxjs';
@Injectable({
providedIn: 'root'
@ -12,7 +11,6 @@ export class ShortcutService {
constructor(private zone: NgZone) {
}
register(shortcut: string, handler: ShortcutHandler) {
console.log("binding key:", shortcut, "to handler", handler);
this.bound.set(handler, shortcut);
return from(register(shortcut, (s) => {
@ -28,12 +26,14 @@ export class ShortcutService {
}
rebind(shortcut: string, handler: ShortcutHandler) {
const prevShortcut = this.bound.get(handler)!;
const prevShortcut = this.bound.get(handler);
this.register(shortcut, handler).subscribe(
{
error: (_err) => {
this.register(prevShortcut, handler);
console.log("Got error during binding, rebinding previous");
if (prevShortcut) {
console.log("Got error during binding, rebinding previous");
this.register(prevShortcut, handler);
}
return EMPTY;
}
});

Loading…
Cancel
Save