diff --git a/core/App/app.go b/core/App/app.go index 86fdb1e..b94ba2b 100644 --- a/core/App/app.go +++ b/core/App/app.go @@ -2,6 +2,10 @@ package app import ( "context" + "fmt" + document "textualize/core/Document" + session "textualize/core/Session" + storage "textualize/storage/Local" ) type App struct { @@ -20,25 +24,12 @@ func GetInstance() *App { func (a *App) Startup(ctx context.Context) { a.Context = ctx -} + localUserData := storage.ReadLocalUserData() + session.InitializeModule(session.Session{ + User: session.User(localUserData), + }) -type Language struct { - DisplayName string - ProcessCode string - TranslateCode string -} + document.InitizeModule() -func GetSuppportedLanguages() []Language { - return []Language{ - { - DisplayName: "English", - ProcessCode: "eng", - TranslateCode: "en", - }, - { - DisplayName: "Hebrew", - ProcessCode: "heb", - TranslateCode: "he", - }, - } + fmt.Println(localUserData) } diff --git a/core/Consts/Consts.go b/core/Consts/Consts.go new file mode 100644 index 0000000..17b6b6e --- /dev/null +++ b/core/Consts/Consts.go @@ -0,0 +1,22 @@ +package consts + +type Language struct { + DisplayName string + ProcessCode string + TranslateCode string +} + +func GetSuppportedLanguages() []Language { + return []Language{ + { + DisplayName: "English", + ProcessCode: "eng", + TranslateCode: "en", + }, + { + DisplayName: "Hebrew", + ProcessCode: "heb", + TranslateCode: "he", + }, + } +} diff --git a/core/Document/Document.go b/core/Document/Document.go index aba446d..ca8b35e 100644 --- a/core/Document/Document.go +++ b/core/Document/Document.go @@ -1,7 +1,7 @@ package document import ( - app "textualize/core/App" + consts "textualize/core/Consts" ) type Entity struct { @@ -11,7 +11,7 @@ type Entity struct { Path string ProjectId string Areas []Area - DefaultLanguage app.Language + DefaultLanguage consts.Language } type Area struct { @@ -21,7 +21,7 @@ type Area struct { StartY int EndX int EndY int - Language app.Language + Language consts.Language Order int } diff --git a/core/Document/DocumentGroup.go b/core/Document/DocumentGroup.go index 71244c1..192f62e 100644 --- a/core/Document/DocumentGroup.go +++ b/core/Document/DocumentGroup.go @@ -5,6 +5,7 @@ type Group struct { ParentId string ProjectId string Name string + Order int } type GroupCollection struct { @@ -26,3 +27,14 @@ func GetGroupCollection() *GroupCollection { func (collection *GroupCollection) AddDocumentGroup(group Group) { collection.Groups = append(collection.Groups, group) } + +func (collection *GroupCollection) GetGroupById(groupId string) *Group { + var foundGroup *Group + + for index, g := range collection.Groups { + if g.Id == groupId { + foundGroup = &collection.Groups[index] + } + } + return foundGroup +} diff --git a/core/Document/ProcessedText.go b/core/Document/ProcessedText.go index 56a8f32..ce0eee9 100644 --- a/core/Document/ProcessedText.go +++ b/core/Document/ProcessedText.go @@ -30,7 +30,7 @@ type ProcessedArea struct { Id string DocumentId string FullText string - Order int // TODO: make reorder feature + Order int Lines []ProcessedLine } diff --git a/core/Session/Project.go b/core/Session/Project.go index f56a645..fe2896f 100644 --- a/core/Session/Project.go +++ b/core/Session/Project.go @@ -1,7 +1,7 @@ package session import ( - app "textualize/core/App" + consts "textualize/core/Consts" ) type Project struct { @@ -12,7 +12,7 @@ type Project struct { } type ProjectSettings struct { - DefaultProcessLanguage app.Language - DefaultTranslateTargetLanguage app.Language + DefaultProcessLanguage consts.Language + DefaultTranslateTargetLanguage consts.Language IsHosted bool } diff --git a/frontend/components/project/Main.tsx b/frontend/components/project/Main.tsx index 129d05c..3c25370 100644 --- a/frontend/components/project/Main.tsx +++ b/frontend/components/project/Main.tsx @@ -6,13 +6,19 @@ import { Fragment, useState } from 'react' import { useNavigation } from '../../context/Navigation/provider' import { mainPages } from '../../context/Navigation/types' import { useProject } from '../../context/Project/provider' +import { GetAllLocalProjects } from '../../wailsjs/wailsjs/go/ipc/Channel' +import { ipc } from '../../wailsjs/wailsjs/go/models' import NewProjectModal from './NewProjectModal' +import ProjectListModal from './ProjectListModal' const MainProject = () => { const [isNewProjectModalOpen, setIsNewProjectModalOpen] = useState(false) + const [isProjectListModal, setIsProjectListModal] = useState(false) const [canPopoverBeOpen, setCanPopoverBeOpen] = useState(true) - const { createNewProject } = useProject() + + const [avalibleProjects, setAvalibleProjects] = useState([]) + const { createNewProject, requestSelectProjectByName } = useProject() const { setSelectedMainPage } = useNavigation() const buttonOptions = [ @@ -31,6 +37,11 @@ const MainProject = () => { icon: , onClick: () => { setCanPopoverBeOpen(false) + GetAllLocalProjects().then(response => { + console.log(response) + setAvalibleProjects(response) + setIsProjectListModal(true) + }) }, }, { @@ -50,10 +61,20 @@ const MainProject = () => { setSelectedMainPage(mainPages.WORKSPACE) } + const onSelectProjectHandler = async (name: string) => { + const successfulResponse = await requestSelectProjectByName(name) + setIsProjectListModal(false) + setCanPopoverBeOpen(true) + + if (successfulResponse) setSelectedMainPage(mainPages.WORKSPACE) + } + return
{isNewProjectModalOpen ? : ''} + {isProjectListModal ? : '' } +
diff --git a/frontend/components/project/ProjectListModal.tsx b/frontend/components/project/ProjectListModal.tsx new file mode 100644 index 0000000..3e9cd78 --- /dev/null +++ b/frontend/components/project/ProjectListModal.tsx @@ -0,0 +1,49 @@ +import { ipc } from '../../wailsjs/wailsjs/go/models' + +type Props = { projects: ipc.Project[], onSelectProjectHandler: (projectName: string) => void } +const ProjectListModal = (props: Props) => { + + return ( +
+ +
+ ) +} + +export default ProjectListModal diff --git a/frontend/components/utils/Search.tsx b/frontend/components/utils/Search.tsx index 7a026f5..07f93bd 100644 --- a/frontend/components/utils/Search.tsx +++ b/frontend/components/utils/Search.tsx @@ -19,6 +19,10 @@ const Search = () => { name: 'Document Workspace', onClick: () => { setSelectedMainPage(mainPages.WORKSPACE) } }, + { + name: 'Change Project', + onClick: () => { setSelectedMainPage(mainPages.SELECTPROJECT) } + }, { name: 'Sign Out', onClick: () => { setSelectedMainPage(mainPages.SELECTPROJECT) } diff --git a/frontend/components/workspace/Sidebar/AreaLineItem.tsx b/frontend/components/workspace/Sidebar/AreaLineItem.tsx index 6ad4171..f44ff3f 100644 --- a/frontend/components/workspace/Sidebar/AreaLineItem.tsx +++ b/frontend/components/workspace/Sidebar/AreaLineItem.tsx @@ -66,7 +66,8 @@ const AreaLineItem = (props: { area: SidebarArea, documentId: string, index: num } const onAreaDropEnd = (areaId: string) => { - const areaDroppedOn = getAreaById(areaId) + const areaDroppedOn = getAreaById(dragOverAreaId) + console.log(areaDroppedOn) if (!areaDroppedOn) return requestChangeAreaOrder(areaId, areaDroppedOn.order) setDragOverAreaId('') diff --git a/frontend/components/workspace/Sidebar/GroupLineItem.tsx b/frontend/components/workspace/Sidebar/GroupLineItem.tsx index 492a34c..171fc62 100644 --- a/frontend/components/workspace/Sidebar/GroupLineItem.tsx +++ b/frontend/components/workspace/Sidebar/GroupLineItem.tsx @@ -1,7 +1,7 @@ 'use client' import { DocumentPlusIcon, PlusIcon, XMarkIcon } from '@heroicons/react/24/outline' -import React, { useRef } from 'react' +import React, { useRef, useState } from 'react' import { useProject } from '../../../context/Project/provider' import classNames from '../../../utils/classNames' import onEnterHandler from '../../../utils/onEnterHandler' @@ -14,9 +14,11 @@ import { SidebarGroup } from './types' const GroupLineItem = (props: { group: SidebarGroup }) => { const { - requestAddDocument + requestAddDocument, + requestChangeGroupOrder, + getGroupById, } = useProject() - + const { selectedGroupId, isAddNewDocumentInputShowing, @@ -28,6 +30,8 @@ const GroupLineItem = (props: { group: SidebarGroup }) => { const addDocumentTextInput = useRef(null) + const [dragOverGroupId, setDragOverGroupId] = useState('') + const onConfirmAddDocumentClickHandler = async (groupId: string) => { const documentName = addDocumentTextInput.current?.value if (!documentName) return @@ -50,6 +54,22 @@ const GroupLineItem = (props: { group: SidebarGroup }) => { setIsAddNewGroupInputShowing(false) } + const onGroupDragOver = (groupId: string) => { + setDragOverGroupId(groupId) + } + + const onGroupDragStart = (groupId: string) => { + setSelectedGroupId(groupId) + } + + const onGroupDropEnd = (groupId: string) => { + const areaDroppedOn = getGroupById(groupId) + console.log('areaDroppedOn', areaDroppedOn) + if (!areaDroppedOn) return + const response = requestChangeGroupOrder(groupId, areaDroppedOn.order) + setDragOverGroupId('') + } + const renderAddNewDocument = (groupId: string) => { return isAddNewDocumentInputShowing && selectedGroupId === groupId ?
@@ -83,7 +103,8 @@ const GroupLineItem = (props: { group: SidebarGroup }) => {
- : { } return (
- - {props.group.name} - -
    - {props.group.documents.map((d, index) => ( - - //
  • - // {!d.areas.length - // ? - //
    onDocumentClickHandler(d.id)} - // onDoubleClick={() => onDocumentDoubleClickHandler(d.id)} - // className={classNames( - // d.id === selectedDocumentId - // ? 'bg-gray-900 text-white' - // : 'text-gray-300 hover:bg-gray-700 hover:text-white', - // 'group items-center py-2 text-base font-medium rounded-b-md pl-10', - // index !== 0 ? 'rounded-t-md' : '', - // )}> - // {selectedDocumentId === d.id && isEditDocumentNameInputShowing - // ? { - // onEnterHandler(event, - // () => onConfirmDocumentNameChangeHandler(event.currentTarget.value)) - // }} - // ref={editDocumentNameTextInput} - // /> - // : - // {d.name} - // - // } - //
    - // :
    - // onDocumentClickHandler(d.id)} - // onDoubleClick={() => onDocumentDoubleClickHandler(d.id)} - // className={classNames( - // d.id === selectedDocumentId - // ? 'bg-gray-900 text-white' - // : 'text-gray-300 hover:bg-gray-700 hover:text-white', - // 'group items-center py-2 text-base font-medium rounded-b-md pl-6', - // index !== 0 ? 'rounded-t-md' : '', + onGroupDragOver(props.group.id)} + onDragEnd={() => onGroupDropEnd(props.group.id)} + className={classNames( + 'group items-center px-2 py-2 text-base font-medium rounded-t-md', + selectedGroupId === props.group.id ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white', + (dragOverGroupId === props.group.id) && props.group.id ? 'bg-gray-300 text-gray-700' : '', + )} + > + {props.group.name} + +
      + {props.group.documents.map((d, index) => ( + + //
    • + // {!d.areas.length + // ? + //
      onDocumentClickHandler(d.id)} + // onDoubleClick={() => onDocumentDoubleClickHandler(d.id)} + // className={classNames( + // d.id === selectedDocumentId + // ? 'bg-gray-900 text-white' + // : 'text-gray-300 hover:bg-gray-700 hover:text-white', + // 'group items-center py-2 text-base font-medium rounded-b-md pl-10', + // index !== 0 ? 'rounded-t-md' : '', + // )}> + // {selectedDocumentId === d.id && isEditDocumentNameInputShowing + // ? { + // onEnterHandler(event, + // () => onConfirmDocumentNameChangeHandler(event.currentTarget.value)) + // }} + // ref={editDocumentNameTextInput} + // /> + // : + // {d.name} + // + // } + //
      + // :
      + // onDocumentClickHandler(d.id)} + // onDoubleClick={() => onDocumentDoubleClickHandler(d.id)} + // className={classNames( + // d.id === selectedDocumentId + // ? 'bg-gray-900 text-white' + // : 'text-gray-300 hover:bg-gray-700 hover:text-white', + // 'group items-center py-2 text-base font-medium rounded-b-md pl-6', + // index !== 0 ? 'rounded-t-md' : '', - // )}> - // {selectedDocumentId === d.id && isEditDocumentNameInputShowing - // ? { - // onEnterHandler(event, - // () => onConfirmDocumentNameChangeHandler(event.currentTarget.value)) - // }} - // ref={editDocumentNameTextInput} - // /> - // : - // {d.name} - // - // } - // - // - //
      - // } - //
    • - ))} + // )}> + // {selectedDocumentId === d.id && isEditDocumentNameInputShowing + // ? { + // onEnterHandler(event, + // () => onConfirmDocumentNameChangeHandler(event.currentTarget.value)) + // }} + // ref={editDocumentNameTextInput} + // /> + // : + // {d.name} + // + // } + //
    + // + //
    + // } + //
  • + ))} - {renderAddNewDocument(props.group.id)} -
-
+ {renderAddNewDocument(props.group.id)} + + ) } diff --git a/frontend/context/Project/makeDefaultProject.ts b/frontend/context/Project/makeDefaultProject.ts index efc901b..54af595 100644 --- a/frontend/context/Project/makeDefaultProject.ts +++ b/frontend/context/Project/makeDefaultProject.ts @@ -26,6 +26,9 @@ const makeDefaultProject = (): ProjectContextType => ({ requestChooseUserAvatar: () => Promise.resolve(''), requestUpdateDocument: ({}) => Promise.resolve(new ipc.Document), requestChangeAreaOrder: (areaId: string, newOrder: number) => Promise.resolve(new ipc.Document()), + requestChangeGroupOrder: (groupId: string, newOrder: number) => Promise.resolve(new ipc.Group()), + getGroupById: (groupId) => undefined, + requestSelectProjectByName: (projectName) => Promise.resolve(false), }) export default makeDefaultProject diff --git a/frontend/context/Project/provider.tsx b/frontend/context/Project/provider.tsx index de20149..88f10ab 100644 --- a/frontend/context/Project/provider.tsx +++ b/frontend/context/Project/provider.tsx @@ -10,6 +10,9 @@ import { RequestUpdateDocument, RequestChangeAreaOrder, RequestDeleteAreaById, + RequestChangeGroupOrder, + GetProjectByName, + RequestChangeSessionProjectByName, } from '../../wailsjs/wailsjs/go/ipc/Channel' import { ipc } from '../../wailsjs/wailsjs/go/models' import { AddAreaProps, AreaProps, ProjectContextType, ProjectProps, UpdateDocumentRequest, UserProps } from './types' @@ -21,6 +24,8 @@ export function useProject() { return useContext(ProjectContext) } +let attempts = 0 + type Props = { children: ReactNode, projectProps: ProjectProps } export function ProjectProvider({ children, projectProps }: Props) { const [documents, setDocuments] = useState(projectProps.documents) @@ -110,6 +115,7 @@ export function ProjectProvider({ children, projectProps }: Props) { const updateSession = async () => { GetCurrentSession().then(response => { if (response) setCurrentSession(response) + console.log(response) Promise.resolve(response) }) } @@ -143,10 +149,34 @@ export function ProjectProvider({ children, projectProps }: Props) { return response } + const getGroupById = (groupId: string): ipc.Group | undefined => ( + groups.find(g => g.id === groupId) + ) + + const requestChangeGroupOrder = async (groupId: string, newOrder: number) => { + const response = await RequestChangeGroupOrder(groupId, newOrder) + await updateDocuments() + return response + } + + const requestSelectProjectByName = async (name: string) => { + const successfulResponse = await RequestChangeSessionProjectByName(name) + await updateSession() + return successfulResponse + } + useEffect(() => { if (!documents.length && !groups.length) updateDocuments() }, [documents.length, groups.length]) + + useEffect(() => { + if ((!currentSession?.user?.localId || !currentSession?.user?.id)) { + updateSession() + attempts++ + } + }, [currentSession?.user?.localId, currentSession?.user?.id]) + const value = { id: '', documents, @@ -172,6 +202,9 @@ export function ProjectProvider({ children, projectProps }: Props) { requestChooseUserAvatar, requestUpdateDocument, requestChangeAreaOrder, + requestChangeGroupOrder, + getGroupById, + requestSelectProjectByName, } return diff --git a/frontend/context/Project/types.ts b/frontend/context/Project/types.ts index 6aa730b..8b3e11b 100644 --- a/frontend/context/Project/types.ts +++ b/frontend/context/Project/types.ts @@ -58,4 +58,7 @@ export type ProjectContextType = { requestChooseUserAvatar: () => Promise requestUpdateDocument: (request: UpdateDocumentRequest) => Promise requestChangeAreaOrder: (areaId: string, newOrder: number) => Promise + requestChangeGroupOrder: (groupId: string, newOrder: number) => Promise + getGroupById: (groupId: string) => ipc.Group | undefined + requestSelectProjectByName: (projectName: string) => Promise } & ProjectProps \ No newline at end of file diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 4aa8a63..ece6adc 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -1,4 +1,5 @@ import { NextPage } from 'next' +import { useEffect, useState } from 'react' import MainHead from '../components/head' import MainProject from '../components/project/Main' import User from '../components/settings/User' @@ -9,7 +10,6 @@ import { mainPages } from '../context/Navigation/types' import { useProject } from '../context/Project/provider' const Home: NextPage = () => { - const { currentSession } = useProject() const { selectedMainPage } = useNavigation() diff --git a/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts b/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts index 6381d23..a254ff4 100755 --- a/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts +++ b/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts @@ -4,6 +4,8 @@ import {ipc} from '../models'; export function CreateNewProject(arg1:string):Promise; +export function GetAllLocalProjects():Promise>; + export function GetAreaById(arg1:string):Promise; export function GetCurrentSession():Promise; @@ -16,6 +18,8 @@ export function GetDocuments():Promise; export function GetProcessedAreasByDocumentId(arg1:string):Promise>; +export function GetProjectByName(arg1:string):Promise; + export function GetSuppportedLanguages():Promise>; export function GetUserMarkdownByDocumentId(arg1:string):Promise; @@ -30,6 +34,10 @@ export function RequestAddProcessedArea(arg1:ipc.ProcessedArea):Promise; +export function RequestChangeGroupOrder(arg1:string,arg2:number):Promise; + +export function RequestChangeSessionProjectByName(arg1:string):Promise; + export function RequestChooseUserAvatar():Promise; export function RequestDeleteAreaById(arg1:string):Promise; diff --git a/frontend/wailsjs/wailsjs/go/ipc/Channel.js b/frontend/wailsjs/wailsjs/go/ipc/Channel.js index 348b272..498d759 100755 --- a/frontend/wailsjs/wailsjs/go/ipc/Channel.js +++ b/frontend/wailsjs/wailsjs/go/ipc/Channel.js @@ -6,6 +6,10 @@ export function CreateNewProject(arg1) { return window['go']['ipc']['Channel']['CreateNewProject'](arg1); } +export function GetAllLocalProjects() { + return window['go']['ipc']['Channel']['GetAllLocalProjects'](); +} + export function GetAreaById(arg1) { return window['go']['ipc']['Channel']['GetAreaById'](arg1); } @@ -30,6 +34,10 @@ export function GetProcessedAreasByDocumentId(arg1) { return window['go']['ipc']['Channel']['GetProcessedAreasByDocumentId'](arg1); } +export function GetProjectByName(arg1) { + return window['go']['ipc']['Channel']['GetProjectByName'](arg1); +} + export function GetSuppportedLanguages() { return window['go']['ipc']['Channel']['GetSuppportedLanguages'](); } @@ -58,6 +66,14 @@ export function RequestChangeAreaOrder(arg1, arg2) { return window['go']['ipc']['Channel']['RequestChangeAreaOrder'](arg1, arg2); } +export function RequestChangeGroupOrder(arg1, arg2) { + return window['go']['ipc']['Channel']['RequestChangeGroupOrder'](arg1, arg2); +} + +export function RequestChangeSessionProjectByName(arg1) { + return window['go']['ipc']['Channel']['RequestChangeSessionProjectByName'](arg1); +} + export function RequestChooseUserAvatar() { return window['go']['ipc']['Channel']['RequestChooseUserAvatar'](); } diff --git a/frontend/wailsjs/wailsjs/go/models.ts b/frontend/wailsjs/wailsjs/go/models.ts index 275fd44..fdf2610 100755 --- a/frontend/wailsjs/wailsjs/go/models.ts +++ b/frontend/wailsjs/wailsjs/go/models.ts @@ -107,6 +107,7 @@ export namespace ipc { parentId: string; projectId: string; name: string; + order: number; static createFrom(source: any = {}) { return new Group(source); @@ -118,6 +119,7 @@ export namespace ipc { this.parentId = source["parentId"]; this.projectId = source["projectId"]; this.name = source["name"]; + this.order = source["order"]; } } export class GetDocumentsResponse { @@ -381,7 +383,7 @@ export namespace ipc { export class ProjectSettings { defaultProcessLanguage: Language; defaultTranslateTargetLanguage: Language; - IsHosted: boolean; + isHosted: boolean; static createFrom(source: any = {}) { return new ProjectSettings(source); @@ -391,7 +393,7 @@ export namespace ipc { if ('string' === typeof source) source = JSON.parse(source); this.defaultProcessLanguage = this.convertValues(source["defaultProcessLanguage"], Language); this.defaultTranslateTargetLanguage = this.convertValues(source["defaultTranslateTargetLanguage"], Language); - this.IsHosted = source["IsHosted"]; + this.isHosted = source["isHosted"]; } convertValues(a: any, classs: any, asMap: boolean = false): any { diff --git a/ipc/Documents.go b/ipc/Documents.go index 3304f31..a85053a 100644 --- a/ipc/Documents.go +++ b/ipc/Documents.go @@ -3,6 +3,7 @@ package ipc import ( "sort" app "textualize/core/App" + consts "textualize/core/Consts" document "textualize/core/Document" session "textualize/core/Session" @@ -67,10 +68,6 @@ func (c *Channel) GetDocuments() GetDocumentsResponse { }) } - // sort.Slice(jsonAreas, func(i, j int) bool { - // return jsonAreas[i].Order < jsonAreas[j].Order - // }) - sort.Slice(jsonAreas, func(i, j int) bool { return jsonAreas[i].Order < jsonAreas[j].Order }) @@ -87,16 +84,24 @@ func (c *Channel) GetDocuments() GetDocumentsResponse { response.Documents = append(response.Documents, jsonDocument) } + jsonGroups := make([]Group, 0) for _, g := range groups { jsonGroup := Group{ Id: g.Id, ParentId: g.ParentId, ProjectId: g.ProjectId, Name: g.Name, + Order: g.Order, } - response.Groups = append(response.Groups, jsonGroup) + jsonGroups = append(jsonGroups, jsonGroup) } + sort.Slice(jsonGroups, func(i, j int) bool { + return jsonGroups[i].Order < jsonGroups[j].Order + }) + + response.Groups = jsonGroups + return response } @@ -176,24 +181,68 @@ func (c *Channel) GetUserMarkdownByDocumentId(documentId string) UserMarkdown { } func (c *Channel) RequestAddDocumentGroup(name string) Group { + groupCollection := document.GetGroupCollection() + newGroup := document.Group{ Id: uuid.NewString(), Name: name, ProjectId: session.GetInstance().Project.Id, + Order: len(groupCollection.Groups), } - document.GetGroupCollection().AddDocumentGroup(newGroup) + groupCollection.AddDocumentGroup(newGroup) response := Group{ Id: newGroup.Id, Name: newGroup.Name, ParentId: newGroup.ParentId, ProjectId: newGroup.ProjectId, + Order: newGroup.Order, } return response } +func (c *Channel) RequestChangeGroupOrder(groupId string, newOrder int) Group { + groupCollection := document.GetGroupCollection() + + // var foundArea document.Area + // for _, a := range documentOfArea.Areas { + // if a.Id == areaId { + // foundArea = a + // break + // } + // } + + // if foundArea.Id == "" { + // return Document{} + // } + + // processedAreasCollection := document.GetProcessedAreaCollection() + + // for index, a := range documentOfArea.Areas { + // if a.Id == areaId { + // documentOfArea.Areas[index].Order = newOrder + // processedAreasCollection.GetAreaById(a.Id).Order = newOrder + // } else if a.Order >= newOrder { + // documentOfArea.Areas[index].Order = a.Order + 1 + // processedAreasCollection.GetAreaById(a.Id).Order = a.Order + 1 + // } + // } + + for _, g := range groupCollection.Groups { + if g.Id == groupId { + // document.GetGroupCollection().Groups[index].Order = newOrder + document.GetGroupCollection().GetGroupById(groupId).Order = newOrder + } else if g.Order >= newOrder { + // document.GetGroupCollection().Groups[index].Order = g.Order + 1 + document.GetGroupCollection().GetGroupById(groupId).Order = g.Order + 1 + } + } + + return Group(*document.GetGroupCollection().GetGroupById(groupId)) +} + func (c *Channel) GetAreaById(areaId string) Area { foundDocument := document.GetDocumentCollection().GetDocumentByAreaId(areaId) @@ -243,7 +292,7 @@ func (c *Channel) RequestAddArea(documentId string, area Area) Area { StartY: area.StartY, EndY: area.EndY, Order: order, - Language: app.Language(area.Language), + Language: consts.Language(area.Language), } foundDocument.AddArea(newArea) @@ -337,7 +386,7 @@ func (c *Channel) RequestUpdateDocument(updatedDocument Document) Document { documentToUpdate.Path = updatedDocument.Path } if updatedDocument.DefaultLanguage.DisplayName != "" { - documentToUpdate.DefaultLanguage = app.Language(updatedDocument.DefaultLanguage) + documentToUpdate.DefaultLanguage = consts.Language(updatedDocument.DefaultLanguage) } return updatedDocument diff --git a/ipc/JsonEntities.go b/ipc/JsonEntities.go index eab8413..2738cc1 100644 --- a/ipc/JsonEntities.go +++ b/ipc/JsonEntities.go @@ -20,6 +20,7 @@ type Group struct { ParentId string `json:"parentId"` ProjectId string `json:"projectId"` Name string `json:"name"` + Order int `json:"order"` } type GroupCollection struct { @@ -110,7 +111,7 @@ type Project struct { type ProjectSettings struct { DefaultProcessLanguage Language `json:"defaultProcessLanguage"` DefaultTranslateTargetLanguage Language `json:"defaultTranslateTargetLanguage"` - IsHosted bool `json:"IsHosted"` + IsHosted bool `json:"isHosted"` } type Session struct { diff --git a/ipc/Session.go b/ipc/Session.go index c9d40d5..4b1bc0c 100644 --- a/ipc/Session.go +++ b/ipc/Session.go @@ -2,7 +2,9 @@ package ipc import ( app "textualize/core/App" + consts "textualize/core/Consts" session "textualize/core/Session" + storage "textualize/storage/Local" "github.com/wailsapp/wails/v2/pkg/runtime" @@ -46,12 +48,24 @@ func (c *Channel) GetCurrentSession() Session { func (c *Channel) CreateNewProject(name string) Session { currentSession := session.GetInstance() - currentSession.Project = session.Project{ + newProject := session.Project{ Id: uuid.NewString(), OrganizationId: currentSession.Project.OrganizationId, Name: name, } + successfulProjectWrite := storage.WriteLocalProjectData(storage.LocalProject{ + Id: uuid.NewString(), + OrganizationId: currentSession.Project.OrganizationId, + Name: name, + }) + + if !successfulProjectWrite { + return Session{} + } + + currentSession.Project = newProject + return c.GetCurrentSession() } @@ -62,24 +76,30 @@ func (c *Channel) GetCurrentUser() User { func (c *Channel) RequestUpdateCurrentUser(updatedUserRequest User) User { sessionInstance := session.GetInstance() - user := session.User(sessionInstance.User) + sessionUser := session.User(sessionInstance.User) - if user.LocalId == "" { - user.LocalId = uuid.NewString() + if sessionUser.LocalId == "" { + sessionUser.LocalId = uuid.NewString() } if updatedUserRequest.FirstName != "" { - user.FirstName = updatedUserRequest.FirstName + sessionUser.FirstName = updatedUserRequest.FirstName } if updatedUserRequest.LastName != "" { - user.LastName = updatedUserRequest.LastName + sessionUser.LastName = updatedUserRequest.LastName } if updatedUserRequest.Email != "" { - user.Email = updatedUserRequest.Email + sessionUser.Email = updatedUserRequest.Email } - user.AvatarPath = updatedUserRequest.AvatarPath + sessionUser.AvatarPath = updatedUserRequest.AvatarPath + + successfulUserWrite := storage.WriteLocalUserData(storage.LocalUser(sessionUser)) + if !successfulUserWrite { + return User{} + } + + sessionInstance.UpdateCurrentUser(sessionUser) - sessionInstance.UpdateCurrentUser(user) return User(sessionInstance.User) } @@ -102,8 +122,68 @@ func (c *Channel) RequestChooseUserAvatar() string { } } +func (c *Channel) GetAllLocalProjects() []Project { + readLocalProjects := storage.ReadAllLocalProjects() + response := make([]Project, 0) + + for _, p := range readLocalProjects { + response = append(response, Project{ + Id: p.Id, + OrganizationId: p.OrganizationId, + Name: p.Name, + Settings: ProjectSettings{ + DefaultProcessLanguage: Language(p.Settings.DefaultProcessLanguage), + DefaultTranslateTargetLanguage: Language(p.Settings.DefaultTranslateTargetLanguage), + IsHosted: p.Settings.IsHosted, + }, + }) + } + + return response +} + +func (c *Channel) GetProjectByName(projectName string) Project { + foundProject := storage.ReadLocalProjectByName(projectName) + + if foundProject.Id == "" { + return Project{} + } + + return Project{ + Id: foundProject.Id, + Name: foundProject.Name, + OrganizationId: foundProject.OrganizationId, + Settings: ProjectSettings{ + DefaultProcessLanguage: Language(foundProject.Settings.DefaultProcessLanguage), + DefaultTranslateTargetLanguage: Language(foundProject.Settings.DefaultTranslateTargetLanguage), + IsHosted: foundProject.Settings.IsHosted, + }, + } +} + +func (c *Channel) RequestChangeSessionProjectByName(projectName string) bool { + foundProject := c.GetProjectByName(projectName) + + if foundProject.Id == "" { + return false + } + + session.GetInstance().Project = session.Project{ + Id: foundProject.Id, + Name: foundProject.Name, + OrganizationId: foundProject.OrganizationId, + Settings: session.ProjectSettings{ + DefaultProcessLanguage: consts.Language(foundProject.Settings.DefaultProcessLanguage), + DefaultTranslateTargetLanguage: consts.Language(foundProject.Settings.DefaultTranslateTargetLanguage), + IsHosted: foundProject.Settings.IsHosted, + }, + } + + return session.GetInstance().Project.Id == foundProject.Id +} + func (c *Channel) GetSuppportedLanguages() []Language { - supportedLanguages := app.GetSuppportedLanguages() + supportedLanguages := consts.GetSuppportedLanguages() var response []Language diff --git a/main.go b/main.go index a6bf926..e3493ae 100644 --- a/main.go +++ b/main.go @@ -7,9 +7,8 @@ import ( "net/http" "os" + ipc "textualize/Ipc" app "textualize/core/App" - document "textualize/core/Document" - ipc "textualize/ipc" "github.com/wailsapp/wails/v2" "github.com/wailsapp/wails/v2/pkg/logger" @@ -50,8 +49,6 @@ var icon []byte func main() { // Create an instance of the app structure app := app.GetInstance() - - document.InitizeModule() ipcChannel := ipc.GetInstance() // Create application with options diff --git a/storage/Local/Interface.go b/storage/Local/Interface.go new file mode 100644 index 0000000..e202052 --- /dev/null +++ b/storage/Local/Interface.go @@ -0,0 +1,150 @@ +package storage + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +func GetLocalStoragePath() string { + homeDir, err := os.UserHomeDir() + applicationName := "/Textualize" + + if err != nil { + return "" + } + + return homeDir + applicationName +} + +func createLocalStorageDirIfNeeded() bool { + localStoragePath := GetLocalStoragePath() + if localStoragePath == "" { + return false + } + + _, directoryError := os.Stat(GetLocalStoragePath()) + directoryDoesNotExist := os.IsNotExist(directoryError) + if !directoryDoesNotExist { + return true + } + + errorCreatingDir := os.Mkdir(localStoragePath, os.ModePerm) + return errorCreatingDir != nil +} + +func createLocalStorageSubDirIfNeeded(relativeSubdirectoryPath string) bool { + localStoragePath := GetLocalStoragePath() + if localStoragePath == "" { + return false + } + + fullLocalStoragePath := GetLocalStoragePath() + relativeSubdirectoryPath + + _, directoryError := os.Stat(fullLocalStoragePath) + directoryDoesNotExist := os.IsNotExist(directoryError) + if !directoryDoesNotExist { + return true + } + + errorCreatingDir := os.MkdirAll(fullLocalStoragePath, os.ModePerm) + return errorCreatingDir != nil +} + +func WriteLocalUserData(user LocalUser) bool { + file, _ := json.MarshalIndent(user, "", " ") + path := GetLocalStoragePath() + + if path == "" { + return false + } + + isLocalStorageDirectoryCreated := createLocalStorageDirIfNeeded() + if !isLocalStorageDirectoryCreated { + return false + } + + err := os.WriteFile(GetLocalStoragePath()+"/User.json", file, 0644) + + return err == nil +} + +func ReadLocalUserData() LocalUser { + + file, err := os.ReadFile(GetLocalStoragePath() + "/User.json") + + if err != nil { + return LocalUser{} + } + + response := LocalUser{} + errorUnmarshaling := json.Unmarshal([]byte(file), &response) + if errorUnmarshaling != nil { + return LocalUser{} + } + + return response +} + +func ReadLocalProjectByName(name string) LocalProject { + file, err := os.ReadFile(GetLocalStoragePath() + "/projects/" + name + ".json") + + if err != nil { + return LocalProject{} + } + + response := LocalProject{} + errorUnmarshaling := json.Unmarshal([]byte(file), &response) + if errorUnmarshaling != nil { + return LocalProject{} + } + + return response +} + +func WriteLocalProjectData(project LocalProject) bool { + file, _ := json.MarshalIndent(project, "", " ") + path := GetLocalStoragePath() + + if path == "" { + return false + } + + subdirectory := "/projects/" + isLocalStorageDirectoryCreated := createLocalStorageSubDirIfNeeded(subdirectory) + if !isLocalStorageDirectoryCreated { + return false + } + + err := os.WriteFile(GetLocalStoragePath()+subdirectory+project.Name+".json", file, 0644) + + return err == nil +} + +func ReadAllLocalProjects() []LocalProject { + localProjects := make([]LocalProject, 0) + + subdirectory := "/projects/" + isLocalStorageDirectoryCreated := createLocalStorageSubDirIfNeeded(subdirectory) + if !isLocalStorageDirectoryCreated { + return localProjects + } + + localProjectFileEntries, readDirError := os.ReadDir(GetLocalStoragePath() + subdirectory) + if readDirError != nil { + fmt.Println(localProjectFileEntries) + return localProjects + } + + localProjectNames := make([]string, 0) + for _, fileName := range localProjectFileEntries { + localProjectNames = append(localProjectNames, strings.ReplaceAll(fileName.Name(), ".json", "")) + } + + for _, projectName := range localProjectNames { + localProjects = append(localProjects, ReadLocalProjectByName(projectName)) + } + + return localProjects +} diff --git a/storage/Local/JsonEntities.go b/storage/Local/JsonEntities.go new file mode 100644 index 0000000..673ea8b --- /dev/null +++ b/storage/Local/JsonEntities.go @@ -0,0 +1,30 @@ +package storage + +type LocalProject struct { + Id string `json:"id"` + OrganizationId string `json:"organizationId"` + Name string `json:"name"` + Settings LocalProjectSettings `json:"settings"` +} + +type LocalProjectSettings struct { + DefaultProcessLanguage Language `json:"defaultProcessLanguage"` + DefaultTranslateTargetLanguage Language `json:"defaultTranslateTargetLanguage"` + IsHosted bool `json:"isHosted"` +} + +type Language struct { + DisplayName string `json:"displayName"` + ProcessCode string `json:"processCode"` + TranslateCode string `json:"translateCode"` +} + +type LocalUser struct { + Id string `json:"id"` + LocalId string `json:"localId"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + AvatarPath string `json:"avatarPath"` + AuthToken string `json:"authToken"` + Email string `json:"email"` +}