Refactored with better posting rules
This commit is contained in:
		
							parent
							
								
									cf91fe1627
								
							
						
					
					
						commit
						75f099ce89
					
				| @ -70,14 +70,15 @@ | ||||
|                 @click="hideSearch"><i class="fas fa-times"></i></a> | ||||
|         </div> | ||||
|         <div class="auto-ads" v-show="isAutopostingAds()"> | ||||
|             <h4>Auto-Posting Ads</h4> | ||||
|             <h4>{{l('admgr.activeHeader')}}</h4> | ||||
|             <div class="update">{{adAutoPostUpdate}}</div> | ||||
| 
 | ||||
| 
 | ||||
|             <div v-show="adAutoPostNextAd" class="next"> | ||||
|                 <h5>Coming Next</h5> | ||||
|                 <h5>{{l('admgr.comingNext')}}</h5> | ||||
|                 <div>{{(adAutoPostNextAd ? adAutoPostNextAd.substr(0, 50) : '')}}...</div> | ||||
|             </div> | ||||
| 
 | ||||
|             <a class="btn btn-sm btn-outline-primary renew-autoposts" @click="renewAutoPosting()">{{l('admgr.renew')}}</a> | ||||
|         </div> | ||||
|         <div class="border-top messages" :class="isChannel(conversation) ? 'messages-' + conversation.mode : undefined" ref="messages" | ||||
|             @scroll="onMessagesScroll" style="flex:1;overflow:auto;margin-top:2px"> | ||||
| @ -117,15 +118,15 @@ | ||||
|                 <ul class="nav nav-pills send-ads-switcher" v-if="isChannel(conversation)" | ||||
|                     style="position:relative;z-index:10;margin-right:5px"> | ||||
|                     <li class="nav-item"> | ||||
|                         <a href="#" :class="{active: !conversation.isSendingAds, disabled: conversation.channel.mode != 'both'}" | ||||
|                         <a href="#" :class="{active: !conversation.isSendingAds, disabled: (conversation.channel.mode != 'both') || (conversation.adManager.isActive())}" | ||||
|                             class="nav-link" @click.prevent="setSendingAds(false)">{{l('channel.mode.chat')}}</a> | ||||
|                     </li> | ||||
|                     <li class="nav-item"> | ||||
|                         <a href="#" :class="{active: conversation.isSendingAds, disabled: conversation.channel.mode != 'both'}" | ||||
|                         <a href="#" :class="{active: conversation.isSendingAds, disabled: (conversation.channel.mode != 'both') || (conversation.adManager.isActive())}" | ||||
|                             class="nav-link" @click.prevent="setSendingAds(true)">{{adsMode}}</a> | ||||
|                     </li> | ||||
|                     <li class="nav-item"> | ||||
|                         <a href="#" :class="{active: conversation.adState.active}" class="nav-link" @click="autoPostAds()">Auto-Post Ads</a> | ||||
|                         <a href="#" :class="{active: conversation.adManager.isActive()}" class="nav-link toggle-autopost" @click="toggleAutoPostAds()">{{l('admgr.toggleAutoPost')}}</a> | ||||
|                     </li> | ||||
|                 </ul> | ||||
|                 <div class="btn btn-sm btn-primary" v-show="!settings.enterSend" @click="sendButton">{{l('chat.send')}}</div> | ||||
| @ -146,7 +147,7 @@ | ||||
|     import {Keys} from '../keys'; | ||||
|     import {BBCodeView, Editor} from './bbcode'; | ||||
|     import CommandHelp from './CommandHelp.vue'; | ||||
|     import { AdState, characterImage, getByteLength, getKey } from "./common"; | ||||
|     import { characterImage, getByteLength, getKey } from "./common"; | ||||
|     import ConversationSettings from './ConversationSettings.vue'; | ||||
|     import core from './core'; | ||||
|     import {Channel, channelModes, Character, Conversation, Settings} from './interfaces'; | ||||
| @ -191,8 +192,8 @@ | ||||
|         adCountdown = 0; | ||||
|         adsMode = l('channel.mode.ads'); | ||||
|         autoPostingUpdater = 0; | ||||
|         adAutoPostUpdate: string|null = null; | ||||
|         adAutoPostNextAd: string|null = null; | ||||
|         adAutoPostUpdate: string | null = null; | ||||
|         adAutoPostNextAd: string | null = null; | ||||
|         isChannel = Conversation.isChannel; | ||||
|         isPrivate = Conversation.isPrivate; | ||||
| 
 | ||||
| @ -236,7 +237,8 @@ | ||||
|                 setAdCountdown(); | ||||
|             }); | ||||
| 
 | ||||
|             this.$watch('conversation.adState.active', () => (this.refreshAutoPostingTimer())); | ||||
|             this.$watch(() => this.conversation.adManager.isActive(), () => (this.refreshAutoPostingTimer())); | ||||
|             this.refreshAutoPostingTimer(); | ||||
|         } | ||||
| 
 | ||||
|         @Hook('destroyed') | ||||
| @ -273,6 +275,7 @@ | ||||
|             if(!anyDialogsShown) (<Editor>this.$refs['textBox']).focus(); | ||||
|             this.$nextTick(() => setTimeout(() => this.messageView.scrollTop = this.messageView.scrollHeight)); | ||||
|             this.scrolledDown = true; | ||||
|             this.refreshAutoPostingTimer(); | ||||
|         } | ||||
| 
 | ||||
|         @Watch('conversation.messages') | ||||
| @ -399,78 +402,29 @@ | ||||
| 
 | ||||
| 
 | ||||
|         isAutopostingAds(): boolean { | ||||
|             return this.conversation.adState.active; | ||||
|             return this.conversation.adManager.isActive(); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         clearAutoPostAds(): void { | ||||
|             if (this.conversation.adState.interval) { | ||||
|                 clearTimeout(this.conversation.adState.interval); | ||||
|             } | ||||
| 
 | ||||
|             this.conversation.adState = new AdState(); | ||||
|         stopAutoPostAds(): void { | ||||
|             this.conversation.adManager.stop(); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         autoPostAds(): void { | ||||
|         renewAutoPosting(): void { | ||||
|             this.conversation.adManager.renew(); | ||||
| 
 | ||||
|             this.refreshAutoPostingTimer(); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         toggleAutoPostAds(): void { | ||||
|             if(this.isAutopostingAds()) { | ||||
|                 this.clearAutoPostAds(); | ||||
|                 this.refreshAutoPostingTimer(); | ||||
|                 return; | ||||
|                 this.stopAutoPostAds(); | ||||
|             } else { | ||||
|                 this.conversation.adManager.start(); | ||||
|             } | ||||
| 
 | ||||
|             const conversation = this.conversation; | ||||
| 
 | ||||
|             /**** Do not use 'this' keyword below this line, it will operate differently than you expect ****/ | ||||
| 
 | ||||
|             const chanConv = (<Conversation.ChannelConversation>conversation); | ||||
| 
 | ||||
|             const adState = conversation.adState; | ||||
|             const initialWait = Math.max(0, chanConv.nextAd - Date.now()) * 1.1; | ||||
| 
 | ||||
|             adState.adIndex = 0; | ||||
| 
 | ||||
|             const sendNextPost = async () => { | ||||
|                 const ads = conversation.settings.adSettings.ads; | ||||
|                 const index = (adState.adIndex || 0); | ||||
| 
 | ||||
|                 if ((ads.length === 0) || ((adState.expireDue) && (adState.expireDue.getTime() < Date.now()))) { | ||||
|                     conversation.adState = new AdState(); | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 const msg = ads[index % ads.length]; | ||||
| 
 | ||||
|                 await chanConv.sendAd(msg); | ||||
| 
 | ||||
|                 const nextInMs = Math.max(0, (chanConv.nextAd - Date.now())) * 1.1; | ||||
| 
 | ||||
|                 adState.adIndex = index + 1; | ||||
|                 adState.nextPostDue = new Date(Date.now() + nextInMs); | ||||
| 
 | ||||
|                 adState.interval = setTimeout( | ||||
|                     async () => { | ||||
|                         await sendNextPost(); | ||||
|                     }, | ||||
|                     nextInMs | ||||
|                 ); | ||||
|             }; | ||||
| 
 | ||||
| 
 | ||||
|             adState.active = true; | ||||
|             adState.nextPostDue = new Date(Date.now() + initialWait); | ||||
|             adState.expireDue = new Date(Date.now() + 2 * 60 * 60 * 1000); | ||||
| 
 | ||||
| 
 | ||||
|             adState.interval = setTimeout( | ||||
|                 async () => { | ||||
|                     adState.firstPost = new Date(); | ||||
| 
 | ||||
|                     await sendNextPost(); | ||||
|                 }, | ||||
|                 initialWait | ||||
|             ); | ||||
| 
 | ||||
|             this.refreshAutoPostingTimer(); | ||||
|         } | ||||
| 
 | ||||
| @ -487,25 +441,28 @@ | ||||
|             } | ||||
| 
 | ||||
|             const updateAutoPostingState = () => { | ||||
|                 const adState = this.conversation.adState; | ||||
|                 const ads = this.conversation.settings.adSettings.ads; | ||||
|                 const adManager = this.conversation.adManager; | ||||
| 
 | ||||
|                 if(ads.length > 0) { | ||||
|                     this.adAutoPostNextAd = ads[(adState.adIndex || 0) % ads.length]; | ||||
|                 this.adAutoPostNextAd = adManager.getNextAd() || null; | ||||
| 
 | ||||
|                     const diff = ((adState.nextPostDue || new Date()).getTime() - Date.now()) / 1000; | ||||
|                     const expDiff = ((adState.expireDue || new Date()).getTime() - Date.now()) / 1000; | ||||
|                 if(this.adAutoPostNextAd) { | ||||
|                     const diff = ((adManager.getNextPostDue() || new Date()).getTime() - Date.now()) / 1000; | ||||
|                     const expDiff = ((adManager.getExpireDue() || new Date()).getTime() - Date.now()) / 1000; | ||||
| 
 | ||||
|                     if((adState.nextPostDue) && (!adState.firstPost)) { | ||||
|                         this.adAutoPostUpdate = `Posting beings in ${Math.floor(diff / 60)}m ${Math.floor(diff % 60)}s`; | ||||
|                     } else { | ||||
|                         this.adAutoPostUpdate = `Next ad in ${Math.floor(diff / 60)}m ${Math.floor(diff % 60)}s`; | ||||
|                     } | ||||
|                     const diffMins = Math.floor(diff / 60); | ||||
|                     const diffSecs = Math.floor(diff % 60); | ||||
|                     const expDiffMins = Math.floor(expDiff / 60); | ||||
|                     const expDiffSecs = Math.floor(expDiff % 60); | ||||
| 
 | ||||
|                     this.adAutoPostUpdate += `, auto-posting expires in ${Math.floor(expDiff / 60)}m ${Math.floor(expDiff % 60)}s`; | ||||
|                     this.adAutoPostUpdate = l( | ||||
|                         ((adManager.getNextPostDue()) && (!adManager.getFirstPost())) ? 'admgr.postingBegins' : 'admgr.nextPostDue', | ||||
|                         diffMins, | ||||
|                         diffSecs | ||||
|                     ) + l('admgr.expiresIn', expDiffMins, expDiffSecs); | ||||
|                 } else { | ||||
|                     this.adAutoPostNextAd = null; | ||||
|                     this.adAutoPostUpdate = 'No ads have been set up -- auto-posting will be cancelled.'; | ||||
| 
 | ||||
|                     this.adAutoPostUpdate = l('admgr.noAds'); | ||||
|                 } | ||||
|             }; | ||||
| 
 | ||||
| @ -514,7 +471,6 @@ | ||||
|             updateAutoPostingState(); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         hasSFC(message: Conversation.Message): message is Conversation.SFCMessage { | ||||
|             return (<Partial<Conversation.SFCMessage>>message).sfc !== undefined; | ||||
|         } | ||||
| @ -559,6 +515,12 @@ | ||||
|             padding: 3px 10px; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         .toggle-autopost { | ||||
|             margin-left: 1px; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         .auto-ads { | ||||
|             background-color: rgba(255, 128, 32, 0.8); | ||||
|             padding-left: 10px; | ||||
| @ -566,6 +528,29 @@ | ||||
|             padding-top: 5px; | ||||
|             padding-bottom: 5px; | ||||
|             margin: 0; | ||||
|             position: relative; | ||||
| 
 | ||||
|             .renew-autoposts { | ||||
|                 display: block; | ||||
|                 float: right; | ||||
|                 /* margin-top: auto; */ | ||||
|                 /* margin-bottom: auto; */ | ||||
|                 position: absolute; | ||||
|                 /* bottom: 1px; */ | ||||
|                 right: 10px; | ||||
|                 top: 50%; | ||||
|                 transform: translateY(-50%); | ||||
|                 border-color: rgba(255, 255, 255, 0.5); | ||||
|                 color: rgba(255, 255, 255, 0.9); | ||||
| 
 | ||||
|                 &:hover { | ||||
|                     background-color: rgba(255, 255, 255, 0.3); | ||||
|                 } | ||||
| 
 | ||||
|                 &:active { | ||||
|                     background-color: rgba(255, 255, 255, 0.6); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             h4 { | ||||
|                 font-size: 1.1rem; | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import {WebSocketConnection} from '../fchat'; | ||||
| 
 | ||||
| export default class Socket implements WebSocketConnection { | ||||
|     static host = 'wss://chat.f-list.net:9799'; | ||||
|     static host = 'wss://chat.f-list.net/chat2'; | ||||
|     private socket: WebSocket; | ||||
|     private lastHandler: Promise<void> = Promise.resolve(); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										120
									
								
								chat/ad-manager.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								chat/ad-manager.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | ||||
| import { Conversation } from './interfaces'; | ||||
| 
 | ||||
| export class AdManager { | ||||
|     static readonly POSTING_PERIOD = 3 * 60 * 60 * 1000; | ||||
|     static readonly START_VARIANCE = 3 * 60 * 1000; | ||||
|     static readonly POST_VARIANCE = 10 * 60 * 1000; | ||||
|     static readonly POST_DELAY = 2 * 60 * 1000; | ||||
| 
 | ||||
|     private conversation: Conversation; | ||||
| 
 | ||||
|     private adIndex = 0; | ||||
|     private active = false; | ||||
|     private nextPostDue?: Date; | ||||
|     private expireDue?: Date; | ||||
|     private firstPost?: Date; | ||||
|     private interval?: any; | ||||
| 
 | ||||
|     constructor(conversation: Conversation) { | ||||
|         this.conversation = conversation; | ||||
|     } | ||||
| 
 | ||||
|     isActive(): boolean { | ||||
|         return this.active; | ||||
|     } | ||||
| 
 | ||||
|     private async sendNextPost(): Promise<void> { | ||||
|         const msg = this.getNextAd(); | ||||
| 
 | ||||
|         if ((!msg) || ((this.expireDue) && (this.expireDue.getTime() < Date.now()))) { | ||||
|             this.stop(); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const chanConv = (<Conversation.ChannelConversation>this.conversation); | ||||
| 
 | ||||
|         await chanConv.sendAd(msg); | ||||
| 
 | ||||
|         // post next ad every 12 - 22 minutes
 | ||||
|         const nextInMs = Math.max(0, (chanConv.nextAd - Date.now())) + | ||||
|             AdManager.POST_DELAY + | ||||
|             Math.random() * AdManager.POST_VARIANCE; | ||||
| 
 | ||||
|         this.adIndex = this.adIndex + 1; | ||||
|         this.nextPostDue = new Date(Date.now() + nextInMs); | ||||
| 
 | ||||
|         this.interval = setTimeout( | ||||
|             async() => { | ||||
|                 await this.sendNextPost(); | ||||
|             }, | ||||
|             nextInMs | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     getAds(): string[] { | ||||
|         return this.conversation.settings.adSettings.ads; | ||||
|     } | ||||
| 
 | ||||
|     getNextAd(): string | undefined { | ||||
|         const ads = this.getAds(); | ||||
| 
 | ||||
|         if (ads.length === 0) | ||||
|             return; | ||||
| 
 | ||||
|         return ads[this.adIndex % ads.length]; | ||||
|     } | ||||
| 
 | ||||
|     getNextPostDue(): Date | undefined { | ||||
|         return this.nextPostDue; | ||||
|     } | ||||
| 
 | ||||
|     getExpireDue(): Date | undefined { | ||||
|         return this.expireDue; | ||||
|     } | ||||
| 
 | ||||
|     getFirstPost(): Date | undefined { | ||||
|         return this.firstPost; | ||||
|     } | ||||
| 
 | ||||
|     start(): void { | ||||
|         const chanConv = (<Conversation.ChannelConversation>this.conversation); | ||||
|         const initialWait = Math.max(Math.random() * AdManager.START_VARIANCE, (chanConv.nextAd - Date.now()) * 1.1); | ||||
| 
 | ||||
|         this.adIndex = 0; | ||||
|         this.active = true; | ||||
|         this.nextPostDue = new Date(Date.now() + initialWait); | ||||
|         this.expireDue = new Date(Date.now() + AdManager.POSTING_PERIOD); | ||||
| 
 | ||||
|         this.interval = setTimeout( | ||||
|             async() => { | ||||
|                 this.firstPost = new Date(); | ||||
| 
 | ||||
|                 await this.sendNextPost(); | ||||
|             }, | ||||
|             initialWait | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     stop(): void { | ||||
|         if (this.interval) | ||||
|             clearTimeout(this.interval); | ||||
| 
 | ||||
|         delete this.interval; | ||||
|         delete this.nextPostDue; | ||||
|         delete this.expireDue; | ||||
|         delete this.firstPost; | ||||
| 
 | ||||
|         this.active = false; | ||||
|         this.adIndex = 0; | ||||
| 
 | ||||
|         // const message = new EventMessage(`Advertisements on channel [channel]${this.conversation.name}[/channel] have expired.`);
 | ||||
|         // addEventMessage(message);
 | ||||
|     } | ||||
| 
 | ||||
|     renew(): void { | ||||
|         if (!this.active) | ||||
|             return; | ||||
| 
 | ||||
|         this.expireDue = new Date(Date.now() + 3 * 60 * 60 * 1000); | ||||
|     } | ||||
| } | ||||
| @ -50,16 +50,6 @@ export class AdSettings implements Conversation.AdSettings { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export class AdState implements Conversation.AdState { | ||||
|     active = false; | ||||
|     firstPost?: Date = undefined; | ||||
|     nextPostDue?: Date = undefined; | ||||
|     interval?: any = undefined; | ||||
|     adIndex?: number = undefined; | ||||
|     expireDue?: Date = undefined; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export class ConversationSettings implements Conversation.Settings { | ||||
|     notify = Conversation.Setting.Default; | ||||
|     highlight = Conversation.Setting.Default; | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import {queuedJoin} from '../fchat/channels'; | ||||
| import {decodeHTML} from '../fchat/common'; | ||||
| import { AdState, characterImage, ConversationSettings, EventMessage, Message, messageToString } from './common'; | ||||
| import { AdManager } from './ad-manager'; | ||||
| import { characterImage, ConversationSettings, EventMessage, Message, messageToString } from './common'; | ||||
| import core from './core'; | ||||
| import {Channel, Character, Conversation as Interfaces} from './interfaces'; | ||||
| import l from './localize'; | ||||
| @ -30,14 +31,15 @@ abstract class Conversation implements Interfaces.Conversation { | ||||
|     infoText = ''; | ||||
|     abstract readonly maxMessageLength: number | undefined; | ||||
|     _settings: Interfaces.Settings | undefined; | ||||
|     _adState: Interfaces.AdState | undefined; | ||||
|     protected abstract context: CommandContext; | ||||
|     protected maxMessages = 50; | ||||
|     protected allMessages: Interfaces.Message[] = []; | ||||
|     readonly reportMessages: Interfaces.Message[] = []; | ||||
|     private lastSent = ''; | ||||
|     adManager: AdManager; | ||||
| 
 | ||||
|     constructor(readonly key: string, public _isPinned: boolean) { | ||||
|         this.adManager = new AdManager(this); | ||||
|     } | ||||
| 
 | ||||
|     get settings(): Interfaces.Settings { | ||||
| @ -50,17 +52,6 @@ abstract class Conversation implements Interfaces.Conversation { | ||||
|         state.setSettings(this.key, value); //tslint:disable-line:no-floating-promises
 | ||||
|     } | ||||
| 
 | ||||
|     get adState(): Interfaces.AdState { | ||||
|         //tslint:disable-next-line:strict-boolean-expressions
 | ||||
|         return this._adState || (this._adState = state.adStates[this.key] || new AdState()); | ||||
|     } | ||||
| 
 | ||||
|     set adState(value: Interfaces.AdState) { | ||||
|         this._adState = value; | ||||
|         state.setAdState(this.key, value); //tslint:disable-line:no-floating-promises
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     get isPinned(): boolean { | ||||
|         return this._isPinned; | ||||
|     } | ||||
| @ -200,12 +191,11 @@ class PrivateConversation extends Conversation implements Interfaces.PrivateConv | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if(this.adState.active) { | ||||
|         if(this.adManager.isActive()) { | ||||
|             this.errorText = 'Cannot send ads manually while ad auto-posting is active'; | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         core.connection.send('PRI', {recipient: this.name, message: this.enteredText}); | ||||
|         const message = createMessage(MessageType.Message, core.characters.ownCharacter, this.enteredText); | ||||
|         this.safeAddMessage(message); | ||||
| @ -331,7 +321,7 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv | ||||
|     protected async doSend(): Promise<void> { | ||||
|         const isAd = this.isSendingAds; | ||||
| 
 | ||||
|         if(this.adState.active) { | ||||
|         if(this.adManager.isActive()) { | ||||
|             this.errorText = 'Cannot post ads manually while ad auto-posting is active'; | ||||
|             return; | ||||
|         } | ||||
| @ -349,7 +339,6 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv | ||||
|         else this.clearText(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     async sendAd(text: string): Promise<void> { | ||||
|         if (text.length < 1) | ||||
|             return; | ||||
| @ -399,7 +388,6 @@ class State implements Interfaces.State { | ||||
|     recentChannels: Interfaces.RecentChannelConversation[] = []; | ||||
|     pinned!: {channels: string[], private: string[]}; | ||||
|     settings!: {[key: string]: Interfaces.Settings}; | ||||
|     adStates: {[key: string]: Interfaces.AdState} = {}; | ||||
|     modes!: {[key: string]: Channel.Mode | undefined}; | ||||
|     windowFocused = document.hasFocus(); | ||||
| 
 | ||||
| @ -444,12 +432,6 @@ class State implements Interfaces.State { | ||||
|         await core.settingsStore.set('conversationSettings', this.settings); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     setAdState(key: string, value: Interfaces.AdState): void { | ||||
|         this.adStates[key] = value; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     show(conversation: Conversation): void { | ||||
|         this.selectedConversation.onHide(); | ||||
|         conversation.unread = Interfaces.UnreadState.None; | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| import {Connection} from '../fchat'; | ||||
| 
 | ||||
| import {Channel, Character} from '../fchat/interfaces'; | ||||
| import { AdManager } from './ad-manager'; | ||||
| export {Connection, Channel, Character} from '../fchat/interfaces'; | ||||
| export const userStatuses: ReadonlyArray<Character.Status> = ['online', 'looking', 'away', 'busy', 'dnd']; | ||||
| export const channelModes: ReadonlyArray<Channel.Mode> = ['chat', 'ads', 'both']; | ||||
| @ -98,22 +99,10 @@ export namespace Conversation { | ||||
|         readonly adSettings: AdSettings; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     export interface AdSettings { | ||||
|         readonly ads: string[]; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     export interface AdState { | ||||
|         active: boolean; | ||||
|         firstPost?: Date; | ||||
|         nextPostDue?: Date; | ||||
|         expireDue?: Date; | ||||
|         interval?: any; | ||||
|         adIndex?: number; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     export const enum UnreadState { None, Unread, Mention } | ||||
| 
 | ||||
|     export interface Conversation { | ||||
| @ -127,7 +116,7 @@ export namespace Conversation { | ||||
|         readonly key: string | ||||
|         readonly unread: UnreadState | ||||
|         settings: Settings | ||||
|         adState: AdState | ||||
|         readonly adManager: AdManager; | ||||
|         send(): Promise<void> | ||||
|         clear(): void | ||||
|         loadLastSent(): void | ||||
|  | ||||
| @ -17,6 +17,14 @@ const strings: {[key: string]: string | undefined} = { | ||||
|     'action.updateAvailable': 'UPDATE AVAILABLE', | ||||
|     'action.update': 'Restart now!', | ||||
|     'action.cancel': 'Cancel', | ||||
|     'admgr.postingBegins': 'Posting beings in {0}m {1}s', | ||||
|     'admgr.nextPostDue': 'Next ad in {0}m {1}s', | ||||
|     'admgr.expiresIn': ', auto-posting expires in {0}m {1}s', | ||||
|     'admgr.noAds': 'No ads have been set up -- auto-posting will be cancelled.', | ||||
|     'admgr.activeHeader': 'Auto-Posting Ads', | ||||
|     'admgr.comingNext': 'Coming Next', | ||||
|     'admgr.renew': 'Renew', | ||||
|     'admgr.toggleAutoPost': 'Auto-Post Ads', | ||||
|     'consoleWarning.head': 'THIS IS THE DANGER ZONE.', | ||||
|     'consoleWarning.body': `ANYTHING YOU WRITE OR PASTE IN HERE COULD BE USED TO STEAL YOUR PASSWORDS OR TAKE OVER YOUR ENTIRE COMPUTER. This is where happiness goes to die. If you aren't a developer or a special kind of daredevil, please get out of here!`, | ||||
|     'help': 'Help', | ||||
|  | ||||
							
								
								
									
										15
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "target": "es2017", | ||||
|     "module": "commonjs", | ||||
|     "sourceMap": true, | ||||
|     "allowJs": true, | ||||
|     "noEmitHelpers": true, | ||||
|     "importHelpers": true, | ||||
|     "forceConsistentCasingInFileNames": true, | ||||
|     "strict": true, | ||||
|     "noUnusedLocals": true, | ||||
|     "noUnusedParameters": true | ||||
|   }, | ||||
|   "include": ["./electron/main.ts"] | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user