Skip to content

Commit

Permalink
Merge pull request #30 from irohalab/refactor/episode-layout
Browse files Browse the repository at this point in the history
Add List Layout for episodes list
  • Loading branch information
EverettSummer authored May 12, 2024
2 parents 036cca0 + 4ac9cd7 commit 613426c
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 35 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mira-ui",
"version": "2.8.2",
"version": "2.9.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
Expand Down
72 changes: 60 additions & 12 deletions src/app/home/bangumi-detail/bangumi-detail.components.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@

import { fromEvent as observableFromEvent, Observable, Subscription } from 'rxjs';
import { fromEvent as observableFromEvent, Subscription } from 'rxjs';

import {filter, tap, mergeMap} from 'rxjs/operators';
import { ChangeDetectorRef, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { HomeChild, HomeService } from "../home.service";
import { Bangumi, User } from "../../entity";
import { Bangumi, Episode, User } from "../../entity";
import { ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { UserService } from '../../user-service';
import { PersistStorage, UserService } from '../../user-service';
import { ChromeExtensionService, ENABLED_STATUS } from '../../browser-extension/chrome-extension.service';
import { DARK_THEME, DarkThemeService, UIDialog, UIToast, UIToastComponent, UIToastRef } from '@irohalab/deneb-ui';
import { AuthError } from '../../../helpers/error';
import { WatchService } from '../watch.service';
import { environment } from '../../../environments/environment';

const LAYOUT_TYPE: string = 'layout_type';
const LAYOUT_TYPES = {
GRID: 'grid_layout',
LIST: 'list_layout'
}

const SORT_ORDER: string = 'bangumi_detail_eps_sort_order';

@Component({
selector: 'view-bangumi-detail',
Expand All @@ -39,6 +46,31 @@ export class BangumiDetail extends HomeChild implements OnInit, OnDestroy {

isDarkTheme: boolean;

layoutType: string;
eLayoutTypes = LAYOUT_TYPES;
sortOrder: 'asc' | 'desc' = 'asc';

private _reversedEpisodeList: Episode[];
get episodeList(): Episode[] {
if (this.sortOrder === 'desc') {
if (!this._reversedEpisodeList) {
let firstUnfinished = -1;
this._reversedEpisodeList = this.bangumi.episodes
.filter((eps, index) => {
if (firstUnfinished === -1 && eps.status !== Episode.STATUS_DOWNLOADED) {
firstUnfinished = index;
return true;
}
return eps.status === Episode.STATUS_DOWNLOADED
})
.reverse();
}
return this._reversedEpisodeList;
} else {
return this.bangumi.episodes;
}
}

constructor(homeService: HomeService,
userService: UserService,
private _darkThemeService: DarkThemeService,
Expand All @@ -48,6 +80,7 @@ export class BangumiDetail extends HomeChild implements OnInit, OnDestroy {
private _titleService: Title,
private _changeDetector: ChangeDetectorRef,
private _watchService: WatchService,
private _persistStorage: PersistStorage,
toast: UIToast) {
super(homeService);
this._toastRef = toast.makeText();
Expand All @@ -59,6 +92,11 @@ export class BangumiDetail extends HomeChild implements OnInit, OnDestroy {
);
}

toggleSortOrder(): void {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
this._persistStorage.setItem(SORT_ORDER, this.sortOrder);
}

toggleCover() {
if (this._coverExpanded) {
this.checkViewport();
Expand All @@ -78,7 +116,14 @@ export class BangumiDetail extends HomeChild implements OnInit, OnDestroy {
);
}

changeLayoutType(layoutType: string): void {
this.layoutType = layoutType;
this._persistStorage.setItem(LAYOUT_TYPE, layoutType);
}

ngOnInit(): void {
this.layoutType = this._persistStorage.getItem(LAYOUT_TYPE, LAYOUT_TYPES.LIST);
this.sortOrder = this._persistStorage.getItem(SORT_ORDER, 'asc') as 'asc' | 'desc';
this._subscription.add(
this._darkThemeService.themeChange
.subscribe(theme => { this.isDarkTheme = theme === DARK_THEME; })
Expand All @@ -104,15 +149,18 @@ export class BangumiDetail extends HomeChild implements OnInit, OnDestroy {
mergeMap(() => {
return this._chromeExtensionService.invokeBangumiMethod('bangumiDetail', [this.bangumi.bgm_id]);
}),)
.subscribe((extraInfo) => {
// console.log(extraInfo);
this.extraInfo = extraInfo;
}, (error) => {
console.log(error);
if (error instanceof AuthError && (error as AuthError).isPermission()) {
this._toastRef.show('没有权限');
} else {
this._toastRef.show(error.message);
.subscribe({
next: (extraInfo) => {
// console.log(extraInfo);
this.extraInfo = extraInfo;
},
error: (error) => {
console.log(error);
if (error instanceof AuthError && (error as AuthError).isPermission()) {
this._toastRef.show('没有权限');
} else {
this._toastRef.show(error.message);
}
}
})
);
Expand Down
14 changes: 13 additions & 1 deletion src/app/home/bangumi-detail/bangumi-detail.dark.less
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,16 @@
.dark-episode-list() {
.episode-list {
background-color: transparent;
.episode-card {
.episode-layout-button-groups {
> .layout-button {
color: @darkLinkColor;
&:focus,
&:hover {
color: @darkLinkHoverColor;
}
}
}
.episode-card, .episode-list-view-item {
background-color: lighten(@darkBackground, 5%);
box-shadow: 0px 1px 3px 0px @darkBoxShadowColor, 0px 0px 0px 1px @darkBoxShadowColor;
.image-fallback {
Expand All @@ -49,6 +58,9 @@
}
.content.unfinished {
color: darken(@darkLinkColor, 10%);
.content-heading {
color: darken(@darkLinkColor, 10%);
}
}
}
}
Expand Down
73 changes: 69 additions & 4 deletions src/app/home/bangumi-detail/bangumi-detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,73 @@ <h3 class="bangumi-title name">
</div>
<div class="episode-list">
<h4 class="episode-list-heading">各话列表</h4>
<div class="episode-layout-button-groups">
<a class="layout-button sort-button" [title]="sortOrder === 'desc' ? '最早在前,显示所有' : '最新在前,仅显示可观看'" (click)="toggleSortOrder()">
<i class="ui sort numeric icon" [ngClass]="{up: sortOrder === 'asc', down: sortOrder === 'desc'}"></i>
</a>
<a class="layout-button" title="网格视图" (click)="changeLayoutType(eLayoutTypes.GRID)"><i class="ui th icon"></i></a>
<a class="layout-button" title="列表视图" (click)="changeLayoutType(eLayoutTypes.LIST)"><i class="ui th list icon"></i></a>
</div>
<div class="ui divider"></div>
<div class="ui six doubling cards">
<div class="card episode-card" *ngFor="let episode of bangumi.episodes">
<div *ngIf="layoutType === eLayoutTypes.LIST" class="episode-list-view ui stackable two column grid">
<div class="column" *ngFor="let episode of episodeList">
<div class="ui segment episode-list-view-item">
<div class="image" *ngIf="episode.status!==2">
<div class="image-wrapper">
<div class="image-fallback">
<h4 class="ui icon film icon-holder">
<i class="film icon"></i>
</h4>
</div>
</div>
</div>
<div *ngIf="episode.status!==2" class="content unfinished">
<div class="content-heading">
<span>第{{episode.episode_no}}话&nbsp;</span>
<span *ngIf="episode.name_cn || episode.name">{{episode.name_cn || episode.name}}</span>
</div>
<div class="extra-info">
<span>时长:&nbsp;{{episode.duration}}</span>
<span>更新时间:{{episode.airdate}}</span>
<span class="ui tiny teal label" *ngIf="sortOrder === 'desc' && episode.status !== 2">即将播出</span>
</div>
</div>
<a *ngIf="episode.status===2" class="image" [routerLink]="['/play', episode.id]">
<responsive-image [src]="episode.thumbnail_image.url"
[size]="{
width: '100%',
ratio: 0.5625,
originalWidth: episode.thumbnail_image.width,
originalHeight: episode.thumbnail_image.height}"
[background]="episode.thumbnail_image.dominant_color"></responsive-image>
</a>
<a *ngIf="episode.status===2" class="content" [routerLink]="['/play', episode.id]">
<div class="content-heading">
<span>第{{episode.episode_no}}话</span>
<span *ngIf="episode.name_cn || episode.name">{{episode.name_cn || episode.name}}</span>
</div>
<div class="extra-info">
<span>时长:&nbsp;{{episode.duration}}</span>
<span>更新时间:{{episode.airdate}}</span>
<span class="ui tiny teal label" *ngIf="sortOrder === 'desc' && episode.status !== 2">即将播出</span>
</div>
</a>
<div class="ui bottom attached progress"
*ngIf="episode.watch_progress && episode.watch_progress.percentage"
[ngClass]="{
orange: episode.watch_progress.watch_status === 1,
olive: episode.watch_progress.watch_status === 2,
blue: episode.watch_progress.watch_status === 3,
brown: episode.watch_progress.watch_status === 4,
grey: episode.watch_progress.watch_status === 5
}">
<div class="bar" [style.width]="episode.watch_progress.percentage * 100 + '%'"></div>
</div>
</div>
</div>
</div>
<div *ngIf="layoutType === eLayoutTypes.GRID" class="ui six doubling cards">
<div class="card episode-card" *ngFor="let episode of episodeList">
<div class="image" *ngIf="episode.status!==2">
<div class="image-wrapper">
<div class="image-fallback">
Expand All @@ -60,7 +124,7 @@ <h4 class="ui icon film icon-holder">
</div>
</div>
<div *ngIf="episode.status!==2" class="content unfinished">
<span>{{episode.episode_no}}话</span>
<span class="episode-title" *ngIf="episode.name_cn || episode.name">{{episode.name_cn || episode.name}}</span>
</div>
<a *ngIf="episode.status===2" class="image" [routerLink]="['/play', episode.id]">
<responsive-image [src]="episode.thumbnail_image.url"
Expand All @@ -71,8 +135,9 @@ <h4 class="ui icon film icon-holder">
originalHeight: episode.thumbnail_image.height}"
[background]="episode.thumbnail_image.dominant_color"></responsive-image>
</a>
<span class="episode-number">{{episode.episode_no}}</span>
<a *ngIf="episode.status===2" class="content" [routerLink]="['/play', episode.id]">
<span>{{episode.episode_no}}话</span>
<span class="episode-title" *ngIf="episode.name_cn || episode.name">{{episode.name_cn || episode.name}}</span>
</a>
<div class="ui bottom attached progress"
*ngIf="episode.watch_progress && episode.watch_progress.percentage"
Expand Down
67 changes: 66 additions & 1 deletion src/app/home/bangumi-detail/bangumi-detail.less
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,27 @@
margin: 0;
padding: 2rem 0 0 0;
}

.episode-layout-button-groups {
position: absolute;
right: 0.4rem;
top: 2.2rem;
> .sort-button {
margin-right: 1.5em;
}
> .layout-button {
display: inline-block;
cursor: pointer;
color: #4c4c4c;
&:focus,
&:hover {
color: #101010;
}
}
}
}

.episode-card {
.episode-card, .episode-list-view {
overflow: hidden;
.image-wrapper {
display: block;
Expand Down Expand Up @@ -210,4 +228,51 @@
min-width: 1rem;
}
}
.episode-number {
position: absolute;
left: 0;
top: 0;
color: #ffffff;
background-color: rgba(0, 0, 0, 0.5);
padding: 0.1em 0.4em;
border-radius: 0 0 0.28571429rem 0 !important;
}
}

.episode-list-view {
@media only screen and (max-width: 767px) {
&.ui.stackable.grid {
margin-left: -1rem !important;
margin-right: -1rem !important;
}
}
.episode-list-view-item {
display: flex;
flex-direction: row;
justify-content: flex-start;
padding: 0;
> .image {
width: 8rem;
flex: 0 0 8rem;
}
> .content {
padding: 0.7em 1em;
.extra-info {
margin-top: 0.2em;
font-size: 0.8rem;
color: #a9a9a9;
> span {
display: inline-block;
}
> span:not(:last-child) {
margin-right: 1.5em;
}
}
}
> .content.unfinished {
.content-heading {
color: #696969;
}
}
}
}
Loading

0 comments on commit 613426c

Please sign in to comment.