Commit 9d58e148 authored by 神楽坂玲奈's avatar 神楽坂玲奈

not work

parent eca92692
......@@ -36,8 +36,9 @@
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {},
"outputPath": "dist/mycard",
"index": "src/index.html",
"main": "src/main.ts",
......@@ -48,7 +49,7 @@
"src/assets"
],
"styles": [
"src/styles.css"
"src/styles.scss"
],
"scripts": []
},
......@@ -86,7 +87,7 @@
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"builder": "@angular-builders/custom-webpack:dev-server",
"configurations": {
"production": {
"browserTarget": "mycard:build:production"
......@@ -98,7 +99,7 @@
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"builder": "@angular-builders/custom-webpack:extract-i18n",
"options": {
"browserTarget": "mycard:build"
}
......
require('@electron/remote/main').initialize()
const { autoUpdater } = require('electron-updater');
// 自动更新
let updateWindow;
global.autoUpdater = autoUpdater;
autoUpdater.on('error', (event) => {
global.update_status = 'error';
console.log('autoUpdater', 'error', event);
});
autoUpdater.on('checking-for-update', () => {
global.update_status = 'checking-for-update';
console.log('autoUpdater', 'checking-for-update');
});
autoUpdater.on('update-available', () => {
global.update_status = 'update-available';
console.log('autoUpdater', 'update-available');
});
autoUpdater.on('update-not-available', () => {
global.update_status = 'update-not-available';
console.log('autoUpdater', 'update-not-available');
});
autoUpdater.on('update-downloaded', (event) => {
global.update_status = 'update-downloaded';
console.log('autoUpdater', 'update-downloaded', event);
// updateWindow = new BrowserWindow({
// width: 640,
// height: 360,
// });
// updateWindow.loadURL(`file://${__dirname}/update.html`);
// updateWindow.webContents.on('new-window', function (e, url) {
// e.preventDefault();
// shell.openExternal(url);
// });
// updateWindow.on('closed', function () {
// updateWindow = null;
// });
// ipcMain.on('update', (event, arg) => {
// autoUpdater.quitAndInstall();
// });
});
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron');
const path = require('path');
......@@ -5,22 +47,24 @@ const path = require('path');
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
width: 1024,
height: 640,
minWidth: 1024,
minHeight: 640,
frame: process.platform === 'darwin',
titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined,
webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, webviewTag: true },
});
// and load the index.html of the app.
if (process['NODE_ENV'] === 'development') {
if (process['NODE_ENV'] !== 'production') {
mainWindow.loadURL('http://localhost:4200');
} else {
mainWindow.loadFile('dist/ci/index.html');
}
// Open the DevTools.
// mainWindow.webContents.openDevTools()
mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
......
This diff is collapsed.
This diff is collapsed.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'mycard';
}
import { NgModule } from '@angular/core';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { WebviewDirective } from './shared/webview.directive';
import { MyCardComponent } from './mycard.component';
// import { WebviewDirective } from './shared/webview.directive';
import { FormsModule } from '@angular/forms';
import { LoginComponent } from './login/login.component';
import { LobbyComponent } from './lobby/lobby.component';
@NgModule({
declarations: [
AppComponent,
WebviewDirective
MyCardComponent,
// WebviewDirective,
LoginComponent,
LobbyComponent
],
imports: [
BrowserModule,
AppRoutingModule
AppRoutingModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
bootstrap: [MyCardComponent],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class AppModule { }
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-lobby',
templateUrl: './lobby.component.html',
styleUrls: ['./lobby.component.css']
})
export class LobbyComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
{{url | json}}
<!--<webview [src]="url" (will-navigate)="return_sso($event.url)" (new-window)="openExternal($event.url)"></webview>-->
/**
* Created by zh99998 on 16/9/2.
*/
import { Component } from '@angular/core';
import { LoginService, User } from './login.service';
import crypto from 'crypto';
import { shell } from 'electron';
@Component({
selector: 'app-login',
templateUrl: 'login.component.html',
styleUrls: ['login.component.css']
})
export class LoginComponent {
url: string;
readonly return_sso_url = 'https://mycard.moe/login_callback'; // 这个url不会真的被使用,可以填写不存在的
constructor(private loginService: LoginService) {
let params = new URLSearchParams();
params.set('return_sso_url', this.return_sso_url);
let payload = Buffer.from(params.toString()).toString('base64');
let url = new URL('https://accounts.moecube.com');
params = url['searchParams'];
params.set('sso', payload);
params.set('sig', crypto.createHmac('sha256', 'zsZv6LXHDwwtUAGa').update(payload).digest('hex'));
this.url = url.toString();
if (this.loginService.logging_out) {
url = new URL('https://ygobbs.com/logout');
params = url['searchParams'];
// params.set('redirect', this.url);
// 暂时 hack 一下登出,因为聊天室现在没办法重新初始化,于是登出后刷新页面。
params.set('redirect', 'https://mycard.moe/logout_callback');
this.url = url.toString();
}
}
return_sso(return_url: string) {
if (return_url === 'https://mycard.moe/logout_callback') {
return location.reload();
}
if (!return_url.startsWith(this.return_sso_url)) {
return;
}
let token = new URL(return_url)['searchParams'].get('sso');
if (!token) {
return;
}
let user: User = <any>Object.fromEntries(new URLSearchParams(Buffer.from(token, 'base64').toString()));
this.loginService.login(user);
}
openExternal(url: string) {
shell.openExternal(url);
}
}
/**
* Created by zh99998 on 2016/10/25.
*/
import { Injectable } from '@angular/core';
export interface User {
admin: boolean;
avatar_url: string;
email: string;
external_id: number;
moderator: boolean;
name: string;
username: string;
}
@Injectable({
providedIn: 'root'
})
export class LoginService {
user: User;
logged_in = false;
logging_out = false;
constructor() {
let data = localStorage.getItem('login');
if (data) {
this.user = JSON.parse(data);
this.logged_in = true;
}
}
login(user: User) {
this.user = user;
this.logged_in = true;
localStorage.setItem('login', JSON.stringify(user));
}
logout() {
this.logging_out = true;
this.logged_in = false;
localStorage.removeItem('login');
}
}
<!--<div class="container">-->
<header class='navbar navbar-light bg-light'>
<a class='navbar-brand' href='#'>
<img class='me-2' src='assets/icon.ico'>
<span class='text-primary'>MyCard</span>
</a>
<ul class="nav me-auto">
<li *ngIf="!loginService.logged_in" class="nav-item active">
<a i18n class="nav-link" href="#">登录</a>
</li>
<!--<li *ngIf="loginService.logged_in" [ngClass]="{active: currentPage === 'store'}" class="nav-item">-->
<!--<a (click)="currentPage = 'store'" class="nav-link" href="#">商店</a>-->
<!--</li>-->
<li *ngIf="loginService.logged_in" [ngClass]="{active: currentPage === 'lobby'}" class="nav-item">
<a i18n (click)="currentPage='lobby'" class="nav-link" href="#">游戏</a>
</li>
<li *ngIf="loginService.logged_in" [ngClass]="{active: currentPage === 'community'}" class="nav-item">
<a i18n (click)="currentPage='community'" class="nav-link" href="#">社区</a>
</li>
<!--<li *ngIf="loginService.logged_in" [ngClass]="{active: currentPage === 'moesound'}" class="nav-item">-->
<!--<a i18n (click)="currentPage='moesound'" class="nav-link" href="#">萌音</a>-->
<!--</li>-->
<!--<li *ngIf="loginService.logged_in" [ngClass]="{active: currentPage === 'about'}" class="nav-item">-->
<!--<a i18n (click)="currentPage='about'" class="nav-link" href="#">关于</a>-->
<!--</li>-->
</ul>
<div id="navbar-right" class='text-secondary'>
<span id="update-status">
<i #error [hidden]="update_status != 'error'" (click)="update_retry()" class="fa fa-exclamation-circle" data-bs-toggle="tooltip" i18n-title title="更新出错,点击重试"></i>
<i #checking_for_update [hidden]="update_status != 'checking-for-update'" class="fa fa-spinner fa-pulse fa-spin" data-bs-toggle="tooltip" i18n-title title="正在检查更新"></i>
<i #update_available [hidden]="update_status != 'update-available'" class="fa fa-refresh fa-spin" data-bs-toggle="tooltip" i18n-title title="正在下载更新"></i>
<i #update_downloaded [hidden]="update_status != 'update-downloaded'" (click)="update_install()" class="fa fa-angle-double-up" data-bs-toggle="tooltip" i18n-title title="下载更新完成,点击安装"></i>
</span>
<span id="user" *ngIf="loginService.logged_in">
<a href="#" class="profile"><img id="avatar" [src]="loginService.user.avatar_url" alt="image"></a>
<a href="#" class="profile item" id="username">{{loginService.user.username}}</a>
<i i18n (click)="loginService.logout()" class="fa fa-sign-out item-icon" aria-hidden="true" i18n-title title="切换用户"></i>
<i i18n data-bs-toggle="modal" data-bs-target="#settings-modal" class="fa fa-cog item-icon" aria-hidden="true" i18n-title title="设置"></i>
</span>
<span id="border">|</span>
<span id="window-buttons">
<i i18n (click)="currentWindow.minimize()" class="fa fa-minus" i18n-title title="最小化"></i>
<i i18n *ngIf="!currentWindow.isMaximized()" (click)="currentWindow.maximize()" class="fa fa-expand" i18n-title title="最大化"></i>
<i i18n *ngIf="currentWindow.isMaximized()" (click)="currentWindow.unmaximize()" class="fa fa-clone" i18n-title title="还原"></i>
<i i18n (click)="currentWindow.hide()" class="fa fa-times" i18n-title title="关闭"></i>
</span>
</div>
</header>
<app-login id='login' class="page" *ngIf="!loginService.logged_in"></app-login>
<!--<store class="page" *ngIf="loginService.logged_in" [hidden]="currentPage != 'store'"></store>-->
<app-lobby class="page" *ngIf="loginService.logged_in" [hidden]="currentPage != 'lobby'"></app-lobby>
<webview class="page" *ngIf="loginService.logged_in" [hidden]="currentPage != 'community'" src="https://ygobbs.com" (new-window)="openExternal($event.url)"></webview>
<!--<about class="page" *ngIf="loginService.logged_in" [hidden]="currentPage != 'about'"></about>-->
<!-- Modal -->
<div class="modal fade" id="settings-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 i18n class="modal-title" id="myModalLabel">MyCard 设置</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form (submit)="submit()">
<div class="modal-body">
<div class="container">
<div class="form-group row">
<label i18n for="locale" class="col-sm-2 col-form-label">语言</label>
<div class="col-sm-10">
<select class="form-control" id="locale" [(ngModel)]="locale" name="locale">
<option value="en-US">English</option>
<option value="zh-CN">简体中文</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button i18n type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button i18n type="submit" class="btn btn-primary" data-bs-dismiss="modal">确定</button>
</div>
</form>
</div>
</div>
</div>
.navbar {
padding: initial;
}
.navbar-brand {
width: 200px;
font-size: 24px;
text-align: center;
img {
width: 28px;
vertical-align: text-bottom;
}
}
.nav {
.nav-link {
font-size: 18px;
color: #a7a7a7;
padding: .8rem 1.2em;
}
.nav-item.active {
background-color: white;
.nav-link {
color: #00a4d9;
}
}
}
#navbar-right {
display: flex;
#avatar {
height: 1.5rem;
}
.item {
display: block;
//float: left;
//padding-top: .425rem;
//padding-bottom: .425rem;
margin: 0 0.8rem;
text-decoration: none;
color: #a7a7a7;
}
}
import { LoginService } from './login/login.service';
import { SettingsService } from './settings.service';
import { Tooltip } from 'bootstrap';
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { app, getCurrentWindow, getGlobal, shell } from '@electron/remote';
import Mousetrap from 'mousetrap';
const autoUpdater: Electron.AutoUpdater = getGlobal('autoUpdater');
@Component({
selector: 'app-root',
templateUrl: 'mycard.component.html',
styleUrls: ['mycard.component.scss']
})
export class MyCardComponent implements OnInit {
currentPage: string = 'lobby';
update_status: string | undefined = getGlobal('update_status');
update_error: string | undefined;
currentWindow = getCurrentWindow();
@ViewChild('error')
error: ElementRef;
@ViewChild('checking_for_update')
checking_for_update: ElementRef;
@ViewChild('update_available')
update_available: ElementRef;
@ViewChild('update_downloaded')
update_downloaded: ElementRef;
update_elements: Map<string, ElementRef<HTMLElement>>;
locale: string;
resizing: HTMLElement | null;
@ViewChild('moesound')
moesound: ElementRef;
lastTooltip: Tooltip;
constructor(public loginService: LoginService, private ref: ChangeDetectorRef, private settingsService: SettingsService) {
this.currentWindow.on('maximize', () => this.ref.detectChanges());
this.currentWindow.on('unmaximize', () => this.ref.detectChanges());
autoUpdater.on('error', (error) => {
console.dir(error);
this.set_update_status('error');
});
autoUpdater.on('checking-for-update', () => {
this.set_update_status('checking-for-update');
});
autoUpdater.on('update-available', () => {
this.set_update_status('update-available');
});
autoUpdater.on('update-not-available', () => {
this.set_update_status('update-not-available');
});
autoUpdater.on('update-downloaded', (event) => {
this.set_update_status('update-downloaded');
});
this.locale = this.settingsService.getLocale();
}
ngOnInit() {
this.update_elements = new Map(Object.entries({
'error': this.error,
'checking-for-update': this.checking_for_update,
'update-available': this.update_available,
'update-downloaded': this.update_downloaded
}));
// https://www.electronjs.org/docs/tutorial/keyboard-shortcuts#%E4%BD%BF%E7%94%A8%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%93
Mousetrap.bind('up up down down left right left right b a', () => this.currentWindow.webContents.openDevTools());
}
update_retry() {
autoUpdater.checkForUpdates();
}
update_install() {
autoUpdater.quitAndInstall();
}
set_update_status(status: string) {
console.log('autoUpdater', status);
if (this.lastTooltip) this.lastTooltip.dispose();
this.update_status = status;
this.ref.detectChanges();
let element = this.update_elements.get(this.update_status)!;
this.lastTooltip = new Tooltip(element.nativeElement, { placement: 'bottom', container: 'body' });
}
openExternal(url: string) {
shell.openExternal(url);
}
submit() {
if (this.locale !== this.settingsService.getLocale()) {
localStorage.setItem(SettingsService.SETTING_LOCALE, this.locale);
app.relaunch();
app.quit();
}
}
//
// moesound_loaded() {
// this.moesound.nativeElement.insertCSS(`
// body > section > header, #bjax-target > div.row.m-t-lg.m-b-lg, #bjax-target > section {
// display: none;
// }
// body > section > section {
// top: 0!important;
// }
// `);
// }
//
// moesound_newwindow(url: string) {
// console.log(url);
// }
}
/**
* Created by weijian on 2016/10/24.
*/
import { Injectable } from '@angular/core';
import path from 'path';
import { app } from '@electron/remote';
export interface Library {
'default': boolean;
path: string;
}
@Injectable({
providedIn: 'root'
})
export class SettingsService {
static SETTING_LIBRARY = 'library';
static defaultLibraries = [
{
'default': true,
path: path.join(app.getPath('appData'), 'MyCardLibrary')
}
];
static SETTING_LOCALE = 'locale';
static defaultLocale = app.getLocale();
locale: string;
libraries: Library[];
getLibraries() {
if (!this.libraries) {
let data = localStorage.getItem(SettingsService.SETTING_LIBRARY);
if (!data) {
this.libraries = SettingsService.defaultLibraries;
localStorage.setItem(SettingsService.SETTING_LIBRARY,
JSON.stringify(SettingsService.defaultLibraries));
} else {
this.libraries = JSON.parse(data);
}
}
return this.libraries;
}
addLibrary(libraryPath: string, isDefault: boolean) {
let libraries = this.getLibraries();
if (isDefault) {
libraries.forEach((l) => {
l.default = false;
});
}
libraries.push({ 'default': isDefault, path: libraryPath });
this.libraries = libraries;
localStorage.setItem(SettingsService.SETTING_LIBRARY, JSON.stringify(libraries));
}
setDefaultLibrary(library: Library) {
let libraries = this.getLibraries();
libraries.forEach((l) => {
l.default = library.path === l.path;
});
this.libraries = libraries;
localStorage.setItem(SettingsService.SETTING_LIBRARY, JSON.stringify(libraries));
}
getDefaultLibrary(): Library {
if (!this.libraries) {
this.getLibraries();
}
let result = this.libraries.find((item) => item.default === true);
if (result) {
return result;
} else {
throw('no default library found');
}
}
getLocale(): string {
if (!this.locale) {
let locale = localStorage.getItem(SettingsService.SETTING_LOCALE);
if (!locale) {
this.locale = SettingsService.defaultLocale;
localStorage.setItem(SettingsService.SETTING_LOCALE, SettingsService.defaultLocale);
} else {
this.locale = locale;
}
}
return this.locale;
}
setLocale(locale: string) {
this.locale = locale;
localStorage.setItem(SettingsService.SETTING_LOCALE, locale);
}
}
import { Directive } from '@angular/core';
@Directive({
selector: 'webview'
})
export class WebviewDirective {
constructor() { }
}
// import { Directive } from '@angular/core';
//
// @Directive({
// selector: 'webview'
// })
// export class WebviewDirective {
//
// constructor() { }
//
// }
......@@ -59,6 +59,10 @@
*/
import 'zone.js'; // Included with Angular CLI.
/******************************************************************
* Load `$localize` - used if i18n tags appear in Angular templates.
*/
import '@angular/localize/init';
/***************************************************************************************************
* APPLICATION IMPORTS
......
/* You can add global styles to this file, and also import other style files */
/* You can add global styles to this file, and also import other style files */
// First override some or all individual color variables
$primary: #00a4d9;
$secondary: #8f5325;
$success: #3e8d63;
$info: #13101c;
$warning: #945707;
$danger: #d62518;
$light: #f7f7f9;
$dark: #343a40;
// Then add them to your custom theme-colors map, together with any additional colors you might need
$theme-colors: (
primary: $primary,
secondary: $secondary,
success: $success,
info: $info,
warning: $warning,
danger: $danger,
light: $light,
dark: $dark,
// add any additional color below
);
// Override whatever Bootstrap variable you want right here
// Then have Bootstrap do it's magic with these new values
@import "~bootstrap/scss/bootstrap";
@import "~@fortawesome/fontawesome-free/css/all";
......@@ -18,8 +18,11 @@
"module": "es2020",
"lib": [
"es2018",
"dom"
]
"dom",
"dom.iterable"
],
"strictPropertyInitialization": false,
"esModuleInterop": true
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
......
module.exports = {
target: 'electron-renderer'
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment