Added scroll to show more results

This commit is contained in:
Geomitron
2020-03-11 23:20:41 -04:00
parent 18afa01e5c
commit 0a2acf9b31
4 changed files with 42 additions and 13 deletions

View File

@@ -2,6 +2,7 @@ import { Component, ViewChild, AfterViewInit } from '@angular/core'
import { ChartSidebarComponent } from './chart-sidebar/chart-sidebar.component' import { ChartSidebarComponent } from './chart-sidebar/chart-sidebar.component'
import { StatusBarComponent } from './status-bar/status-bar.component' import { StatusBarComponent } from './status-bar/status-bar.component'
import { ResultTableComponent } from './result-table/result-table.component' import { ResultTableComponent } from './result-table/result-table.component'
import { SearchService } from 'src/app/core/services/search.service'
@Component({ @Component({
selector: 'app-browse', selector: 'app-browse',
@@ -14,7 +15,7 @@ export class BrowseComponent implements AfterViewInit {
@ViewChild('chartSidebar', { static: true }) chartSidebar: ChartSidebarComponent @ViewChild('chartSidebar', { static: true }) chartSidebar: ChartSidebarComponent
@ViewChild('statusBar', { static: true }) statusBar: StatusBarComponent @ViewChild('statusBar', { static: true }) statusBar: StatusBarComponent
constructor() { } constructor(private searchService: SearchService) { }
ngAfterViewInit() { ngAfterViewInit() {
const $tableColumn = $('#table-column') const $tableColumn = $('#table-column')
@@ -27,14 +28,9 @@ export class BrowseComponent implements AfterViewInit {
let pos = $tableColumn[0].scrollTop + $tableColumn[0].offsetHeight let pos = $tableColumn[0].scrollTop + $tableColumn[0].offsetHeight
let max = $tableColumn[0].scrollHeight let max = $tableColumn[0].scrollHeight
if (pos >= max - 5) { if (pos >= max - 5) {
// TODO: load more results (should be debounced or something; wait until results have loaded before sending the request for more) this.searchService.updateScroll()
console.log('UPDATE SCROLL')
} }
} }
}) })
} }
loadMoreResults() {
// TODO: use the same query as the current search, but append more results if there are any more to be viewed
}
} }

View File

@@ -1,6 +1,6 @@
import { Injectable, EventEmitter } from '@angular/core' import { Injectable, EventEmitter } from '@angular/core'
import { ElectronService } from './electron.service' import { ElectronService } from './electron.service'
import { SearchType, SongResult } from 'src/electron/shared/interfaces/search.interface' import { SearchType, SongResult, SongSearch } from 'src/electron/shared/interfaces/search.interface'
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -10,11 +10,24 @@ export class SearchService {
private resultsChangedEmitter = new EventEmitter<SongResult[]>() // For when any results change private resultsChangedEmitter = new EventEmitter<SongResult[]>() // For when any results change
private newResultsEmitter = new EventEmitter<SongResult[]>() // For when a new search happens private newResultsEmitter = new EventEmitter<SongResult[]>() // For when a new search happens
private results: SongResult[] = [] private results: SongResult[] = []
private awaitingResults = false
private currentQuery: SongSearch
private allResultsVisible = true
constructor(private electronService: ElectronService) { } constructor(private electronService: ElectronService) { }
async newSearch(query: string) { async newSearch(query: string) {
this.results = await this.electronService.invoke('song-search', { query, type: SearchType.Any }) this.awaitingResults = true
this.currentQuery = { query, type: SearchType.Any, offset: 0, length: 20 + 1 } // TODO: make length a setting
this.results = await this.electronService.invoke('song-search', this.currentQuery)
if (this.results.length > 20) {
this.results.splice(20, 1)
this.allResultsVisible = false
} else {
this.allResultsVisible = true
}
this.awaitingResults = false
this.newResultsEmitter.emit(this.results) this.newResultsEmitter.emit(this.results)
this.resultsChangedEmitter.emit(this.results) this.resultsChangedEmitter.emit(this.results)
} }
@@ -30,4 +43,22 @@ export class SearchService {
get resultCount() { get resultCount() {
return this.results.length return this.results.length
} }
async updateScroll() {
if (!this.awaitingResults && !this.allResultsVisible) {
this.awaitingResults = true
this.currentQuery.offset += 20
const newResults = await this.electronService.invoke('song-search', this.currentQuery)
if (newResults.length > 20) {
newResults.splice(20, 1)
this.allResultsVisible = false
} else {
this.allResultsVisible = true
}
this.results.push(...newResults)
this.awaitingResults = false
this.resultsChangedEmitter.emit(this.results)
}
}
} }

View File

@@ -23,7 +23,7 @@ class SearchHandler implements IPCInvokeHandler<'song-search'> {
*/ */
private getSearchQuery(search: SongSearch) { private getSearchQuery(search: SongSearch) {
switch (search.type) { switch (search.type) {
case SearchType.Any: return this.getGeneralSearchQuery(search.query) case SearchType.Any: return this.getGeneralSearchQuery(search)
default: return '<<<ERROR>>>' // TODO: add more search types default: return '<<<ERROR>>>' // TODO: add more search types
} }
} }
@@ -31,12 +31,12 @@ class SearchHandler implements IPCInvokeHandler<'song-search'> {
/** /**
* @returns a database query that returns the top 20 songs that match `search`. * @returns a database query that returns the top 20 songs that match `search`.
*/ */
private getGeneralSearchQuery(searchString: string) { private getGeneralSearchQuery(search: SongSearch) {
return ` return `
SELECT id, name, artist, album, genre, year SELECT id, name, artist, album, genre, year
FROM Song FROM Song
WHERE MATCH (name,artist,album,genre) AGAINST (${escape(searchString)}) > 0 WHERE MATCH (name,artist,album,genre) AGAINST (${escape(search.query)}) > 0
LIMIT ${20} OFFSET ${0}; LIMIT ${search.length} OFFSET ${search.offset};
` // TODO: add parameters for the limit and offset ` // TODO: add parameters for the limit and offset
} }
} }

View File

@@ -4,6 +4,8 @@
export interface SongSearch { export interface SongSearch {
query: string query: string
type: SearchType type: SearchType
offset: number
length: number
} }
/** /**