Skip to content

Commit

Permalink
Merge custom event dev branch
Browse files Browse the repository at this point in the history
  • Loading branch information
Vaccarini-Lorenzo authored Nov 15, 2023
2 parents f188010 + 1ce75cf commit a099a46
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 40 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ It might happen that some patterns are incorrectly recognized as calendar events
<img width="650" src="https://raw.githubusercontent.com/Vaccarini-Lorenzo/MagicCalendar/main/materials/MagicCalendarNLPBanDemo.gif">
</p>

On the other hand, it could be possible that some patterns are not recognized. You can use your custom delimitators to define an event:

<p align="center">
<img width="650" src="https://raw.githubusercontent.com/Vaccarini-Lorenzo/MagicCalendar/main/materials/CustomEventDemo.gif">
</p>

## Inline event view
Embed your events in your notes with a simple syntax. <br>
The Inline event view is two-way synchronized *(at the moment supported only by Apple Calendar. Google Calendar push notification need an HTTPS server)*.
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "magic-calendar",
"name": "MagicCalendar",
"version": "1.1.7",
"version": "1.1.9",
"minAppVersion": "0.15.0",
"description": "AI-Powered Obsidian Plugin that leverage Natural Language Processing techniques to find calendar events in Markdown notes, seamlessly synchronizing them with a calendar of choice.",
"author": "Vaccarini Lorenzo",
Expand Down
Binary file added materials/CustomEventDemo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "magic-calendar",
"version": "1.1.7",
"version": "1.1.9",
"description": "",
"main": "main.js",
"scripts": {
Expand Down
10 changes: 7 additions & 3 deletions src/controllers/googleCalendarController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,17 @@ export class GoogleCalendarController implements CloudController {
}

injectSettings(settings: SettingInterface) {
this._settings = settings;
this._settings = settings;
if (this._calendars.length == 0){
this._currentCalendarName = this._settings.calendar;
return;
}
this._currentCalendarName = this._calendars.filter(calendar => {
return calendar.summary == this._settings.calendar;
}).first().summary;
this._currentCalendarId = this._calendars.filter(calendar => calendar.summary == this._currentCalendarName).first().id;
const currentCalendar = this._calendars.filter(calendar => calendar.summary == this._currentCalendarName).first();
if (currentCalendar) this._currentCalendarId = currentCalendar.id;
else console.warn("Could not inject settings: Current calendar not found");
}

async tryAuthentication(auth: Map<string,string>): Promise<CloudStatus> {
Expand Down Expand Up @@ -117,7 +119,9 @@ export class GoogleCalendarController implements CloudController {
const calendarResponse = await this._calendarEndpoint.calendarList.list();
this._calendars = calendarResponse.data.items as GoogleCalendar[];
if (!this._currentCalendarName) return;
this._currentCalendarId = this._calendars.filter(calendar => calendar.summary == this._currentCalendarName).first().id;
const currentCalendar = this._calendars.filter(calendar => calendar.summary == this._currentCalendarName).first();
if (currentCalendar) this._currentCalendarId = currentCalendar.id;
else console.warn("Couldn't find current calendar");
}

getCalendarNames() {
Expand Down
53 changes: 46 additions & 7 deletions src/controllers/nlpController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,26 @@ class NlpController {
const selectedDate = dates[0];
const selectedDateIndex = caseInsensitiveText.indexOf(selectedDate.value);

if (this._setting.customSymbol != "" ){
const customEvent = this.getCustomEvent(sentence);
if (customEvent){
const cleanDates = this.cleanJunkDates(dates);
const dateRange = this.parseDates(cleanDates);
if (!dateRange) return;
sentence.injectSemanticFields(dateRange.start, dateRange.end, customEvent.value)
matchedEvent = eventController.semanticCheck(sentence);
// Matched semantic check;
if (matchedEvent) return null;
const selection = this.getSelectionArray(sentence.value, cleanDates, customEvent);
const event = eventController.createNewEvent(sentence);

return {
selection,
event
}
}
}

// Find purpose in text
// e.g. "to discuss finances"
const purpose = this.filterPurpose(caseInsensitiveText, mainCustomEntities, tokens);
Expand Down Expand Up @@ -391,28 +411,28 @@ class NlpController {
return selectedProperName;
}

private getSelectionArray(text: string, dates: {value, index, type}[], selectedEventNoun: {value, index, type}, backwardsAdjAttributes: {value, index, type}[],
forwardAdjAttributes: {value, index, type}[], selectedProperName: {value, index, type}, purpose: {value, index, type}): {value, index, type}[] {
private getSelectionArray(text: string, dates: {value, index, type}[], selectedEventNoun: {value, index, type}, backwardsAdjAttributes?: {value, index, type}[],
forwardAdjAttributes?: {value, index, type}[], selectedProperName?: {value, index, type}, purpose?: {value, index, type}): {value, index, type}[] {
const selection = []

dates.forEach(date => {
const dateIndex = text.indexOf(date.value);
selection.push({value: date.value, index: dateIndex, type: date.type});
})

if (selectedEventNoun!= null) selection.push(selectedEventNoun);
if (selectedProperName!= null) selection.push(selectedProperName);
if (backwardsAdjAttributes != null){
if (selectedEventNoun) selection.push(selectedEventNoun);
if (selectedProperName) selection.push(selectedProperName);
if (backwardsAdjAttributes){
backwardsAdjAttributes.forEach(backwardsAdjAttribute => {
selection.push(backwardsAdjAttribute);
})
}
if (forwardAdjAttributes != null){
if (forwardAdjAttributes){
forwardAdjAttributes.forEach(forwardAdjAttribute => {
selection.push(forwardAdjAttribute);
})
}
if (purpose != null) selection.push(purpose);
if (purpose) selection.push(purpose);

// Order by index (builder.add needs to be called with increasing values)
return selection.sort((a, b) => a.index - b.index);
Expand Down Expand Up @@ -467,6 +487,25 @@ class NlpController {
if(!this._setting.bannedPatterns) return false;
return this._setting.bannedPatterns.some(bannedPattern => sentence.value.indexOf(bannedPattern) > -1);
}

private getCustomEvent(sentence: Sentence) {
const chars = sentence.value.split("");
let startIndex;
let endIndex;
for (let i=0; i<sentence.value.length - this._setting.customSymbol.length; i++){
const substring = sentence.value.slice(i, i + this._setting.customSymbol.length);
if (substring != this._setting.customSymbol) continue;
if (startIndex == undefined) startIndex = i;
else endIndex = i;
}
if (!endIndex) return;
return {
value: sentence.value.slice(startIndex + this._setting.customSymbol.length, endIndex),
index: startIndex,
type: "customEvent"
}

}
}

const nplController = new NlpController();
Expand Down
24 changes: 19 additions & 5 deletions src/plugin/appSetting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {App, PluginSettingTab, Setting, TextAreaComponent, TextComponent} from "
import MagicCalendar from "./main";
import moment, {tz} from "moment-timezone";
import {CalendarProvider} from "../model/cloudCalendar/calendarProvider";
import {BannedListHTML} from "./bannedListHTML";
import {settingListHTML} from "./settingListHTML";

export interface SettingInterface {
tz: string;
Expand All @@ -11,6 +11,7 @@ export interface SettingInterface {
iv: string;
calendarProvider: CalendarProvider;
bannedPatterns: string[];
customSymbol: string;
}

export const DEFAULT_SETTINGS: Partial<SettingInterface> = {
Expand All @@ -19,6 +20,8 @@ export const DEFAULT_SETTINGS: Partial<SettingInterface> = {
key: "none",
iv: "none",
calendarProvider: CalendarProvider.NOT_SELECTED,
bannedPatterns: [],
customSymbol: ""
};

export class AppSetting extends PluginSettingTab {
Expand All @@ -28,7 +31,9 @@ export class AppSetting extends PluginSettingTab {
key: string;
iv: string;
bannedPatternText: TextComponent;
bannedListHTML: BannedListHTML;
bannedListHTML: settingListHTML;
customPatternText: TextComponent;
customSymbolHTML: settingListHTML;


constructor(app: App, plugin: MagicCalendar) {
Expand Down Expand Up @@ -77,8 +82,6 @@ export class AppSetting extends PluginSettingTab {
})
})

containerEl.createEl("h3", {text: "Advanced"});

new Setting(containerEl)
.setName("Encryption key")
.addText(key => {
Expand All @@ -99,6 +102,17 @@ export class AppSetting extends PluginSettingTab {
})
})

new Setting(containerEl)
.setName("Custom symbol")
.addText(async text => {
text.setPlaceholder("N/A")
text.setValue(this.plugin.settings.customSymbol)
text.onChange(async value => {
this.plugin.settings.customSymbol = value;
await this.plugin.updateSettings();
})
})

new Setting(containerEl)
.setName("Ban pattern")
.addText(text => {
Expand All @@ -114,7 +128,7 @@ export class AppSetting extends PluginSettingTab {
})
})

this.bannedListHTML = new BannedListHTML(containerEl, this.updateBannedPatterns.bind(this), this.plugin.settings.bannedPatterns)
this.bannedListHTML = new settingListHTML(containerEl, this.updateBannedPatterns.bind(this), this.plugin.settings.bannedPatterns)
this.bannedListHTML
.build()
}
Expand Down
13 changes: 3 additions & 10 deletions src/plugin/nlpExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,15 @@ class NLPPlugin implements PluginValue {
const documentLines = view.state.doc.slice(view.viewport.from, view.viewport.to).toJSON();
documentLines.some((line, i) => {
const matches = nplController.process(new Sentence(filePath, line));
if(matches == null) return false;
if(!matches) return false;
const eventDetailString = this.getEventDetail(matches.event);
matches.selection.forEach(match => {
const matchMetadata = this.getMatchTextMetadata(documentLines, view.viewport.from, i, line, match);
if(matchMetadata == null) return;
if(!matchMetadata) return;
const decoration = this.getDecoration(matches.selection, match, matchMetadata, (sync) => {
/*
if (!iCloudController.isLoggedIn()){
new Notice("You're not logged in! 🥲\nLook for iCalSync in the command palette to log in")
return;
}
*/
eventController.processEvent(filePath, sync);
view.setState(view.state);
}, eventDetailString);

try{
builder.add(
matchMetadata.startsFrom,
Expand All @@ -66,7 +59,7 @@ class NLPPlugin implements PluginValue {
for (let j=0; j < currentIndex; j++){
previousChars += documentLines[j].length + 1;
}
const indexOfMatch = line.toLowerCase().indexOf(match.value);
const indexOfMatch = line.toLowerCase().indexOf(match.value.toLowerCase());
if(indexOfMatch == -1) return null;
const capitalizedMatch = line.substring(indexOfMatch, indexOfMatch + match.value.length)
const startsFrom = previousChars + indexOfMatch;
Expand Down
27 changes: 15 additions & 12 deletions src/plugin/bannedListHTML.ts → src/plugin/settingListHTML.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,46 @@ import {Setting} from "obsidian";
import {Misc} from "../misc/misc";
import {Media} from "../misc/media";

export class BannedListHTML extends Setting {
export class settingListHTML extends Setting {
containerEl: HTMLElement;
bannedPatterns: string[];
elements: string[];
listContainer: HTMLElement;
maxLength?: number;
deleteCallback: (pattern: string) => void;

constructor(containerEl: HTMLElement, deleteCallback :(pattern: string) => void, bannedPatterns: string[]) {
constructor(containerEl: HTMLElement, deleteCallback :(pattern: string) => void, elements: string[], maxLength?: number) {
super(containerEl);
this.containerEl = containerEl;
this.bannedPatterns = bannedPatterns;
this.elements = elements;
this.deleteCallback = deleteCallback;
this.listContainer = this.containerEl.createEl("div", { cls: "magicCalendarSettingListContainer" });
this.maxLength = maxLength;
}

build(){
this.listContainer.empty();

this.bannedPatterns.forEach(bannedPattern => {
this.createListElement(bannedPattern)
if (!this.elements) return;
this.elements.forEach(element => {
this.createListElement(element)
});
}

createListElement(bannedPattern: string){
createListElement(element: string){
const listItem = this.listContainer.createEl("div", { cls: "magicCalendarSettingListItem" });
const itemText = listItem.createEl("span", { cls: "magicCalendarSettingListText" });
itemText.setText(bannedPattern);
itemText.setText(element);
const trashIcon = listItem.createEl("img", { cls: "magicCalendarSettingListDeleteIcon" });
trashIcon.setAttribute("src", Media.getBase64DeleteIcon());
trashIcon.onClickEvent(click => {
this.bannedPatterns.remove(bannedPattern);
this.elements.remove(element);
this.build();
this.deleteCallback(bannedPattern);
this.deleteCallback(element);
})
}

append(bannedPattern: string) {
this.bannedPatterns.push(bannedPattern);
if (this.maxLength && this.elements.length >= this.maxLength) this.elements.pop();
this.elements.unshift(bannedPattern);
this.build();
}
}
7 changes: 6 additions & 1 deletion styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@
border-radius: 5px;
float: right; /* This aligns the container to the right */
border: none; /* This removes the border */
width: 100%;
display: block;
flex-direction: column;
}

.magicCalendarSettingListContainer::-webkit-scrollbar {
Expand All @@ -107,7 +110,9 @@
}

.magicCalendarSettingListText {
flex-grow: 1;
text-align: right;
display: block;
width: 100%;
}

.magicCalendarSettingListDeleteIcon {
Expand Down

0 comments on commit a099a46

Please sign in to comment.