diff --git a/documents/업무/3월/3째주/0316 b/documents/업무/3월/3째주/0316 index c2b3ac7..3511a45 100644 --- a/documents/업무/3월/3째주/0316 +++ b/documents/업무/3월/3째주/0316 @@ -4,4 +4,5 @@ PC 이슈 처리 클립보드 팝업 추가 포커스 아웃시 알림 오지 않음 - \ No newline at end of file + +notification.service backup \ No newline at end of file diff --git a/documents/업무/3월/3째주/notification.service.ts b/documents/업무/3월/3째주/notification.service.ts new file mode 100644 index 0000000..bc1b087 --- /dev/null +++ b/documents/업무/3월/3째주/notification.service.ts @@ -0,0 +1,878 @@ +import { delGroupSuccess, buddy2 } from './../store/messenger/sync/actions'; +import { Injectable, Inject } from '@angular/core'; + +import { tap, withLatestFrom, take } from 'rxjs/operators'; + +import { Store, select } from '@ngrx/store'; + +import { + SSVC_TYPE_LOGOUT_RES, + SSVC_TYPE_LOGOUT_REMOTE_NOTI, + AuthenticationProtocolService, + LogoutResponse, + LogoutRemoteNotification, + LogoutNotification, + LoginResponse +} from '@ucap-webmessenger/protocol-authentication'; + +import { NGXLogger } from 'ngx-logger'; +import { + EventProtocolService, + SSVC_TYPE_EVENT_SEND_NOTI, + SendNotification, + SSVC_TYPE_EVENT_READ_NOTI, + SSVC_TYPE_EVENT_CANCEL_NOTI, + SSVC_TYPE_EVENT_DEL_RES, + SSVC_TYPE_EVENT_SEND_RES, + SSVC_TYPE_EVENT_READ_RES, + EventType +} from '@ucap-webmessenger/protocol-event'; +import { + InfoProtocolService, + SSVC_TYPE_INFO_USER_NOTI, + SSVC_TYPE_INFO_USER_RES, + UserNotification +} from '@ucap-webmessenger/protocol-info'; +import { + RoomProtocolService, + SSVC_TYPE_ROOM_INVITE_NOTI, + SSVC_TYPE_ROOM_EXIT_NOTI, + SSVC_TYPE_ROOM_EXIT_FORCING_NOTI, + SSVC_TYPE_ROOM_FONT_UPD_NOTI, + InviteNotification, + UpdateNotification as RoomUpdateNotification, + SSVC_TYPE_ROOM_UPD_RES, + SSVC_TYPE_ROOM_EXIT_FORCING_RES, + SSVC_TYPE_ROOM_EXIT_RES, + SSVC_TYPE_ROOM_INVITE_RES, + ExitForcingResponse, + RoomInfo, + UserInfo, + UserInfoShort +} from '@ucap-webmessenger/protocol-room'; +import { + StatusProtocolService, + SSVC_TYPE_STATUS_NOTI, + StatusNotification +} from '@ucap-webmessenger/protocol-status'; +import { + ReadNotification, + CancelNotification, + DelNotification +} from '@ucap-webmessenger/protocol-event'; +import { + ExitNotification, + ExitForcingNotification, + UpdateFontNotification +} from '@ucap-webmessenger/protocol-room'; +import { + GroupProtocolService, + SSVC_TYPE_GROUP_UPD_RES2, + UpdateNotification as GroupUpdateNotification, + SSVC_TYPE_GROUP_ADD_RES, + AddNotification as GroupAddNotification, + SSVC_TYPE_GROUP_DEL_RES, + DelNotification as GroupDelNotification +} from '@ucap-webmessenger/protocol-group'; +import { + BuddyProtocolService, + SSVC_TYPE_BUDDY_UPD_RES, + UpdateNotification as BuddyUpdateNotification, + SSVC_TYPE_BUDDY_ADD_RES, + AddNotification as BuddyAddNotification, + SSVC_TYPE_BUDDY_DEL_RES, + DelNotification as BuddyDelNotification +} from '@ucap-webmessenger/protocol-buddy'; +import { + SyncProtocolService, + PhoneBookSyncType, + SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI, + SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI, + PhoneBookSndNotification, + RoomUserData +} from '@ucap-webmessenger/protocol-sync'; + +import * as AppStore from '@app/store'; +import * as AuthenticationStore from '@app/store/account/authentication'; +import * as InfoStore from '@app/store/account/info'; +import * as EventStore from '@app/store/messenger/event'; +import * as SyncStore from '@app/store/messenger/sync'; +import * as RoomStore from '@app/store/messenger/room'; +import * as StatusStore from '@app/store/messenger/status'; +import { + NotificationRequest, + NativeService, + UCAP_NATIVE_SERVICE, + NotificationType, + WindowState +} from '@ucap-webmessenger/native'; +import { StringUtil, DialogService } from '@ucap-webmessenger/ui'; + +import { + LocalStorageService, + SessionStorageService +} from '@ucap-webmessenger/web-storage'; +import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type'; + +import { environment } from '../../environments/environment'; +import { NotificationMethod } from '@ucap-webmessenger/core'; +import { Dictionary } from '@ngrx/entity'; +import { MessageType } from '@ucap-webmessenger/api-message'; +import { LogoutInfo, KEY_LOGOUT_INFO } from '@app/types'; +import { TranslateService } from '@ngx-translate/core'; +import { deleteMessageSuccess } from '@app/store/messenger/message'; +import { ServerErrorCode } from '@ucap-webmessenger/protocol'; +import { + OptionProtocolService, + SSVC_TYPE_OPTION_REG_UPD_RES, + RegUpdateResponse, + RegUpdateNotification +} from '@ucap-webmessenger/protocol-option'; +import { + GeneralSetting, + Settings, + NotificationSetting, + ChatSetting +} from '@ucap-webmessenger/ui-settings'; +import clone from 'clone'; + +@Injectable() +export class AppNotificationService { + constructor( + private authenticationProtocolService: AuthenticationProtocolService, + private eventProtocolService: EventProtocolService, + private infoProtocolService: InfoProtocolService, + private roomProtocolService: RoomProtocolService, + private groupProtocolService: GroupProtocolService, + private buddyProtocolService: BuddyProtocolService, + private statusProtocolService: StatusProtocolService, + private translateService: TranslateService, + private syncProtocolService: SyncProtocolService, + private optionProtocolService: OptionProtocolService, + // 쪽지 비활성화 2020-0226 + // private umgProtocolService: UmgProtocolService, + private localStorageService: LocalStorageService, + private sessionStorageService: SessionStorageService, + @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService, + private dialogService: DialogService, + private store: Store, + private logger: NGXLogger + ) {} + + public subscribe(): void { + this.authenticationProtocolService.logoutNotification$ + .pipe( + tap(notiOrRes => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_LOGOUT_RES: + { + const res = notiOrRes as LogoutNotification; + this.logger.debug( + 'Notification::authenticationProtocolService::LogoutResponse', + res + ); + + this.sessionStorageService.set(KEY_LOGOUT_INFO, { + personLogout: true, + reasonCode: res.reasonCode, + ip: res.ip, + mac: res.mac + } as LogoutInfo); + } + break; + case SSVC_TYPE_LOGOUT_REMOTE_NOTI: + { + const noti = notiOrRes as LogoutRemoteNotification; + this.logger.debug( + 'Notification::authenticationProtocolService::LogoutRemoteNotification', + noti + ); + + this.sessionStorageService.set(KEY_LOGOUT_INFO, { + personLogout: true, + reasonCode: ServerErrorCode.ERRCD_FORCE_INIT, + forceType: noti.requestDeviceType + } as LogoutInfo); + } + break; + default: + break; + } + this.dialogService.closeAll(); + + this.store.dispatch(AuthenticationStore.loginRedirect()); + }) + ) + .subscribe(); + + this.eventProtocolService.notification$ + .pipe( + withLatestFrom( + this.store.pipe( + select((state: any) => state.messenger.room.roomInfo as RoomInfo) + ), + this.store.pipe( + select( + (state: any) => + state.messenger.sync.room.entities as Dictionary + ) + ), + this.store.pipe( + select( + (state: any) => + state.messenger.sync.roomUserShort.entities as Dictionary< + RoomUserData + > + ) + ) + ), + tap(([notiOrRes, curRoomInfo, roomList, roomUserShorts]) => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_EVENT_SEND_RES: + case SSVC_TYPE_EVENT_SEND_NOTI: + { + const noti = notiOrRes as SendNotification; + this.logger.debug( + 'Notification::eventProtocolService::SendNotification', + noti + ); + + this.store.dispatch( + EventStore.sendNotification({ + noti + }) + ); + + // notification.. + if (notiOrRes.SSVC_TYPE === SSVC_TYPE_EVENT_SEND_NOTI) { + let doNoti = true; + + // 방별 알림이 꺼져 있으면 노티 안함. + if ( + !!roomList[noti.roomSeq] && + !roomList[noti.roomSeq].receiveAlarm + ) { + doNoti = false; + } + + const windowState = this.nativeService.getWindowState(); + + // 현재 열려 있는 방일경우 노티 안함. + if ( + !!curRoomInfo && + !!curRoomInfo.roomSeq && + curRoomInfo.roomSeq === noti.roomSeq && + !!windowState && + windowState !== WindowState.Minimized && + windowState !== WindowState.Hidden + ) { + doNoti = false; + } + + if (doNoti) { + // const dd = roomUserShorts..filter(u => u.seq === noti.SENDER_SEQ ); + const roomUsers = roomUserShorts[noti.roomSeq]; + let senderUser: UserInfoShort; + + const senderUserTemp = roomUsers.userInfos.filter( + userInfo => { + if (!!userInfo && !!userInfo.seq) { + return userInfo.seq === noti.SENDER_SEQ; + } + } + ); + + senderUser = senderUserTemp[0]; + const appUserInfo = this.localStorageService.encGet< + AppUserInfo + >(KEY_APP_USER_INFO, environment.customConfig.appKey); + + if (appUserInfo.settings.notification.use) { + if ( + appUserInfo.settings.notification.method === + NotificationMethod.Sound + ) { + const audio = new Audio( + 'assets/sounds/messageAlarm.mp3' + ); + audio.play(); + } else { + // const userTemp = userInfoList.filter(user => { user.seq === noti.SENDER_SEQ }); + let contents = StringUtil.convertFinalEventMessage( + noti.eventType, + noti.info.sentMessageJson + ); + + if (!appUserInfo.settings.notification.preView) { + contents = ''; + } + + if (!!contents || contents === '') { + const notiReq: NotificationRequest = { + type: NotificationType.Event, + seq: noti.roomSeq, + title: + senderUser.name + + '
' + + this.translateService.instant( + 'notification.titleChatEventArrived' + ), + contents, + image: senderUser.profileImageFile, + useSound: [ + NotificationMethod.Sound, + NotificationMethod.SoundAndAlert + ].some( + n => + n === appUserInfo.settings.notification.method + ) + ? true + : false, + displayTime: + appUserInfo.settings.notification + .alertExposureTime * 1000 + }; + this.nativeService.notify(notiReq); + } + } + } + } + } + } + break; + case SSVC_TYPE_EVENT_READ_RES: + case SSVC_TYPE_EVENT_READ_NOTI: + { + // 대화방 unread count 처리. + const noti = notiOrRes as ReadNotification; + this.logger.debug( + 'Notification::eventProtocolService::ReadNotification', + noti + ); + this.store.dispatch(EventStore.readNotification(noti)); + } + break; + case SSVC_TYPE_EVENT_CANCEL_NOTI: + { + const noti = notiOrRes as CancelNotification; + this.logger.debug( + 'Notification::eventProtocolService::CancelNotification', + noti + ); + this.store.dispatch( + EventStore.cancelNotification({ + noti + }) + ); + } + break; + case SSVC_TYPE_EVENT_DEL_RES: + { + const noti = notiOrRes as DelNotification; + this.logger.debug( + 'Notification::eventProtocolService::DelNotification', + noti + ); + this.store.dispatch( + EventStore.delNotification({ + noti + }) + ); + } + break; + default: + break; + } + }) + ) + .subscribe(); + this.infoProtocolService.notification$ + .pipe( + tap(notiOrRes => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_INFO_USER_NOTI: + case SSVC_TYPE_INFO_USER_RES: + { + const noti = notiOrRes as UserNotification; + this.logger.debug( + 'Notification::infoProtocolService::UserNotification', + noti + ); + this.store.dispatch( + InfoStore.userNotification({ + noti + }) + ); + } + break; + default: + break; + } + }) + ) + .subscribe(); + this.groupProtocolService.notification$ + .pipe( + withLatestFrom( + this.store.pipe( + select( + (state: any) => state.messenger.sync.group2.syncDate as string + ) + ) + ), + tap(([notiOrRes, syncDate]) => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_GROUP_UPD_RES2: + { + const noti = notiOrRes as GroupUpdateNotification; + this.logger.debug( + 'Notification::groupProtocolService::GroupUpdateNotification', + noti + ); + this.store.dispatch( + SyncStore.group2({ + syncDate + }) + ); + } + break; + case SSVC_TYPE_GROUP_ADD_RES: + { + const noti = notiOrRes as GroupAddNotification; + this.logger.debug( + 'Notification::groupProtocolService::GroupAddNotification', + noti + ); + this.store.dispatch(SyncStore.createGroupSuccess(noti)); + } + break; + case SSVC_TYPE_GROUP_DEL_RES: + { + const noti = notiOrRes as GroupDelNotification; + this.logger.debug( + 'Notification::groupProtocolService::GroupDelNotification', + noti + ); + this.store.dispatch(SyncStore.delGroupSuccess(noti)); + } + break; + + default: + break; + } + }) + ) + .subscribe(); + this.buddyProtocolService.notification$ + .pipe( + withLatestFrom( + this.store.pipe( + select( + (state: any) => state.messenger.sync.buddy2.syncDate as string + ) + ) + ), + tap(([notiOrRes, syncDate]) => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_BUDDY_UPD_RES: + { + const noti = notiOrRes as BuddyUpdateNotification; + this.logger.debug( + 'Notification::groupProtocolService::BuddyUpdateNotification', + noti + ); + this.store.dispatch(SyncStore.updateBuddySuccess(noti)); + } + break; + case SSVC_TYPE_BUDDY_ADD_RES: + { + const noti = notiOrRes as BuddyAddNotification; + this.logger.debug( + 'Notification::groupProtocolService::BuddyAddNotification', + noti + ); + this.store.dispatch(SyncStore.buddy2({ syncDate })); + } + break; + case SSVC_TYPE_BUDDY_DEL_RES: + { + const noti = notiOrRes as BuddyDelNotification; + this.logger.debug( + 'Notification::groupProtocolService::BuddyDelNotification', + noti + ); + this.store.dispatch(SyncStore.delBuddySuccess(noti)); + } + break; + + default: + break; + } + }) + ) + .subscribe(); + this.roomProtocolService.notification$ + .pipe( + withLatestFrom( + this.store.pipe( + select( + (state: any) => + state.account.authentication.loginRes as LoginResponse + ) + ) + ), + tap(([notiOrRes, loginResInfo]) => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_ROOM_INVITE_RES: + case SSVC_TYPE_ROOM_INVITE_NOTI: + { + const noti = notiOrRes as InviteNotification; + this.logger.debug( + 'Notification::roomProtocolService::InviteNotification', + noti + ); + this.store.dispatch( + RoomStore.inviteNotification({ + noti + }) + ); + } + break; + case SSVC_TYPE_ROOM_UPD_RES: + { + const noti = notiOrRes as RoomUpdateNotification; + this.logger.debug( + 'Notification::roomProtocolService::RoomUpdateNotification', + noti + ); + this.store.dispatch( + RoomStore.updateSuccess({ + res: { + roomSeq: noti.roomSeq, + roomName: + noti.roomName.trim().length === 0 + ? ' ' + : noti.roomName.trim(), + receiveAlarm: noti.receiveAlarm, + syncAll: false + } + }) + ); + } + break; + case SSVC_TYPE_ROOM_EXIT_RES: + case SSVC_TYPE_ROOM_EXIT_NOTI: + { + const noti = notiOrRes as ExitNotification; + this.logger.debug( + 'Notification::roomProtocolService::ExitNotification', + noti + ); + + if (noti.SENDER_SEQ === loginResInfo.userSeq) { + this.store.dispatch( + RoomStore.exitNotification({ + noti + }) + ); + } else { + this.store.dispatch( + RoomStore.exitNotificationOthers({ + roomSeq: noti.roomSeq, + trgtUser: [noti.SENDER_SEQ] + }) + ); + + if (!!noti && !!noti.SENDER_SEQ) { + this.store.dispatch( + SyncStore.clearRoomUsers({ + roomSeq: noti.roomSeq, + userSeqs: [noti.SENDER_SEQ] + }) + ); + } + } + } + break; + case SSVC_TYPE_ROOM_EXIT_FORCING_RES: + { + // 내가 강퇴 진행. + const res = notiOrRes as ExitForcingResponse; + this.logger.debug( + 'Notification::roomProtocolService::ExitForcingNotification RES', + res + ); + this.store.dispatch( + RoomStore.exitForcingSuccess({ + res + }) + ); + } + break; + case SSVC_TYPE_ROOM_EXIT_FORCING_NOTI: + { + const noti = notiOrRes as ExitForcingNotification; + this.logger.debug( + 'Notification::roomProtocolService::ExitForcingNotification NOTI', + noti + ); + + if (noti.userSeqs.indexOf(loginResInfo.userSeq) >= 0) { + // 강퇴 대상이 본인이면 열려 있는 대화방을 닫고, 대화리스트에서 삭제. + this.store.dispatch( + RoomStore.exitForcingNotification({ + noti + }) + ); + } else { + // ROOM::열려 있는 대화방에서 강퇴 인원의 isJoinRoom = false 로 변경. + this.store.dispatch( + RoomStore.exitNotificationOthers({ + roomSeq: noti.roomSeq, + trgtUser: noti.userSeqs + }) + ); + + // SYNC::대화리스트의 대화자정보에서 강퇴 인원의 isJoinRoom = false 로 변경. + this.store.dispatch( + SyncStore.clearRoomUsers({ + roomSeq: noti.roomSeq, + userSeqs: noti.userSeqs + }) + ); + } + } + break; + case SSVC_TYPE_ROOM_FONT_UPD_NOTI: + { + const noti = notiOrRes as UpdateFontNotification; + this.logger.debug( + 'Notification::roomProtocolService::UpdateFontNotification', + noti + ); + this.store.dispatch( + RoomStore.updateFontNotification({ + noti + }) + ); + } + break; + default: + break; + } + }) + ) + .subscribe(); + this.statusProtocolService.notification$ + .pipe( + tap(notiOrRes => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_STATUS_NOTI: + { + const noti = notiOrRes as StatusNotification; + this.logger.debug( + 'Notification::statusProtocolService::StatusNotification', + noti + ); + this.store.dispatch( + StatusStore.statusNotification({ + noti + }) + ); + } + break; + default: + break; + } + }) + ) + .subscribe(); + this.optionProtocolService.notification$ + .pipe( + tap(notiOrRes => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_OPTION_REG_UPD_RES: + { + const noti = notiOrRes as RegUpdateNotification; + this.logger.debug( + 'Notification::optionProtocolService::RegUpdateNotification', + noti + ); + + const appUserInfo: AppUserInfo = this.localStorageService.encGet< + AppUserInfo + >(KEY_APP_USER_INFO, environment.customConfig.appKey); + + const modifiedSettings: Settings = clone(appUserInfo.settings); + // 모바일에서 해당 값만 수정함. + modifiedSettings.notification.receiveForMobile = + noti.mobileNotification; + appUserInfo.settings = modifiedSettings; + + this.localStorageService.encSet( + KEY_APP_USER_INFO, + appUserInfo, + environment.customConfig.appKey + ); + } + break; + default: + break; + } + }) + ) + .subscribe(); + this.syncProtocolService.notification$ + .pipe( + tap(notiOrRes => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI: + { + this.logger.debug( + 'Notification::syncProtocolService::SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI', + notiOrRes + ); + + // destination ?: PhoneBookSyncType; + // // (W: 전체(Whole)) (W: 부분(Part)) + // syncType ?: + // PhoneBook ready ok dispatch + this.store.dispatch( + SyncStore.phoneBookReadyOk({ + req: { + syncReadyOk: PhoneBookSyncType.OK_Y, + syncType: PhoneBookSyncType.SYNC_TYPE_WHOLE + } + }) + ); + } + break; + case SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI: + { + this.logger.debug( + 'Notification::syncProtocolService::SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI', + notiOrRes + ); + // PhoneBook sed noti dispatch (data parse) + const noti = notiOrRes as PhoneBookSndNotification; + this.store.dispatch( + SyncStore.phoneBookSndNotification({ + noti + }) + ); + } + break; + default: + break; + } + }) + ) + .subscribe(); + } +} + +/* +쪽지 비활성화 2020-0226 +this.umgProtocolService.notification$ + .pipe( + tap(notiOrRes => { + switch (notiOrRes.SSVC_TYPE) { + case SSVC_TYPE_UMG_NOTI: + { + const noti = notiOrRes as UmgNotiNotification; + this.logger.debug( + 'Notification::umgProtocolService::UmgNotiNotification', + noti + ); + + // unreadCount refresh.. + this.store.dispatch(MessageStore.retrieveUnreadCount({})); + + // Receive Message List refresh.. + this.store.dispatch( + MessageStore.retrieveMessage({ + messageType: MessageType.Receive + }) + ); + + // notification.. + const appUserInfo = this.localStorageService.encGet( + KEY_APP_USER_INFO, + environment.customConfig.appKey + ); + + if (appUserInfo.settings.notification.use) { + if ( + appUserInfo.settings.notification.method === + NotificationMethod.Sound + ) { + const audio = new Audio('assets/sounds/messageAlarm.mp3'); + audio.play(); + } else { + const notiReq: NotificationRequest = { + type: NotificationType.Message, + seq: noti.keyId, + title: this.translateService.instant( + 'notification.titleMessageArrived' + ), + contents: noti.text, + image: noti.senderInfo.profileImageFile, + useSound: [ + NotificationMethod.Sound, + NotificationMethod.SoundAndAlert + ].some(n => n === appUserInfo.settings.notification.method) + ? true + : false, + displayTime: + appUserInfo.settings.notification.alertExposureTime * 1000 + }; + this.nativeService.notify(notiReq); + } + } + + // direct open detail + if (appUserInfo.settings.notification.receiveForMessage) { + this.store.dispatch( + MessageStore.detailMessage({ + messageType: MessageType.Receive, + msgId: Number(noti.keyId) + }) + ); + } + } + break; + case SSVC_TYPE_UMG_DELETE_NOTI: + { + const noti = notiOrRes as UmgDeleteNotiNotification; + this.logger.debug( + 'Notification::umgProtocolService::UmgDeleteNotiNotification', + noti + ); + + // Remove one Receive Message + if (!!noti && !!noti.keyId) { + // clear badge in left navi + this.store.dispatch(MessageStore.retrieveUnreadCount({})); + + // delete message in receive message list + this.store.dispatch( + deleteMessageSuccess({ + messageType: MessageType.Receive, + msgList: [ + { + msgId: Number(noti.keyId) + } + ] + }) + ); + } + } + break; + + default: + break; + } + }) + ) + .subscribe(); +*/ diff --git a/documents/업무/Issue_doc/lftalk/Issue_2020.03.16 (LF Messenger)_박병은.xlsx b/documents/업무/Issue_doc/lftalk/Issue_2020.03.16 (LF Messenger)_박병은.xlsx index 391491a..23ad0bf 100644 Binary files a/documents/업무/Issue_doc/lftalk/Issue_2020.03.16 (LF Messenger)_박병은.xlsx and b/documents/업무/Issue_doc/lftalk/Issue_2020.03.16 (LF Messenger)_박병은.xlsx differ diff --git a/documents/업무/디자인가이드/LF봇 이미지 적용 가이드(Android).pptx b/documents/업무/디자인가이드/LF봇 이미지 적용 가이드(Android).pptx new file mode 100644 index 0000000..8460d70 Binary files /dev/null and b/documents/업무/디자인가이드/LF봇 이미지 적용 가이드(Android).pptx differ