morethanwords
4 years ago
19 changed files with 498 additions and 212 deletions
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
export default function RadioForm(radios: {container: HTMLElement, input: HTMLInputElement}[], onChange: (value: string) => void) { |
||||
const form = document.createElement('form'); |
||||
|
||||
radios.forEach(r => { |
||||
const {container, input} = r; |
||||
form.append(container); |
||||
input.addEventListener('change', () => { |
||||
if(input.checked) { |
||||
onChange(input.value); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
return form; |
||||
} |
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
import CheckboxField from "./checkbox"; |
||||
import RadioField from "./radioField"; |
||||
import { ripple } from "./ripple"; |
||||
import { SliderSuperTab } from "./slider"; |
||||
import RadioForm from "./radioForm"; |
||||
|
||||
export default class Row { |
||||
public container: HTMLElement; |
||||
public title: HTMLDivElement; |
||||
public subtitle: HTMLElement; |
||||
|
||||
public checkboxField: ReturnType<typeof CheckboxField>; |
||||
public radioField: ReturnType<typeof RadioField>; |
||||
|
||||
constructor(options: Partial<{ |
||||
icon: string, |
||||
subtitle: string, |
||||
radioField: Row['radioField'], |
||||
checkboxField: Row['checkboxField'], |
||||
title: string, |
||||
clickable: boolean, |
||||
navigationTab: SliderSuperTab |
||||
}> = {}) { |
||||
this.container = document.createElement('div'); |
||||
this.container.classList.add('row'); |
||||
|
||||
this.subtitle = document.createElement('div'); |
||||
this.subtitle.classList.add('row-subtitle'); |
||||
if(options.subtitle) { |
||||
this.subtitle.innerHTML = options.subtitle; |
||||
} |
||||
|
||||
let havePadding = false; |
||||
if(options.radioField || options.checkboxField) { |
||||
havePadding = true; |
||||
if(options.radioField) { |
||||
this.radioField = options.radioField; |
||||
this.container.append(this.radioField.label); |
||||
} |
||||
|
||||
if(options.checkboxField) { |
||||
this.checkboxField = options.checkboxField; |
||||
this.container.append(this.checkboxField.label); |
||||
} |
||||
} else { |
||||
if(options.title) { |
||||
this.title = document.createElement('div'); |
||||
this.title.classList.add('row-title'); |
||||
this.title.innerHTML = options.title; |
||||
this.container.append(this.title); |
||||
} |
||||
|
||||
if(options.icon) { |
||||
havePadding = true; |
||||
this.title.classList.add('tgico', 'tgico-' + options.icon); |
||||
} |
||||
} |
||||
|
||||
if(havePadding) { |
||||
this.container.classList.add('row-with-padding'); |
||||
} |
||||
|
||||
if(options.navigationTab) { |
||||
this.container.addEventListener('click', () => { |
||||
options.navigationTab.open(); |
||||
}); |
||||
options.clickable = true; |
||||
} |
||||
|
||||
if(options.clickable) { |
||||
this.container.classList.add('row-clickable', 'hover-effect'); |
||||
ripple(this.container); |
||||
} |
||||
|
||||
this.container.append(this.subtitle); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
export const RadioFormFromRows = (rows: Row[], onChange: (value: string) => void) => { |
||||
return RadioForm(rows.map(r => ({container: r.container, input: r.radioField.input})), onChange); |
||||
}; |
@ -0,0 +1,98 @@
@@ -0,0 +1,98 @@
|
||||
import SidebarSlider, { SliderSuperTab } from "../../slider"; |
||||
import { generateSection } from ".."; |
||||
import Row from "../../row"; |
||||
import { InputPrivacyKey, PrivacyRule } from "../../../layer"; |
||||
import appPrivacyManager from "../../../lib/appManagers/appPrivacyManager"; |
||||
import AppPrivacyPhoneNumberTab from "./privacy/phoneNumber"; |
||||
|
||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTab { |
||||
constructor(slider: SidebarSlider) { |
||||
super(slider); |
||||
} |
||||
|
||||
protected init() { |
||||
this.container.classList.add('privacy-container'); |
||||
this.title.innerText = 'Privacy and Security'; |
||||
|
||||
const section = generateSection.bind(null, this.scrollable); |
||||
|
||||
{ |
||||
const container = section(''); |
||||
|
||||
const blockedUsersRow = new Row({ |
||||
icon: 'deleteuser', |
||||
title: 'Blocked Users', |
||||
subtitle: '6 users', |
||||
clickable: true |
||||
}); |
||||
|
||||
const twoFactorRow = new Row({ |
||||
icon: 'lock', |
||||
title: 'Two-Step Verification', |
||||
subtitle: 'Off', |
||||
clickable: true |
||||
}); |
||||
|
||||
const activeSessionRow = new Row({ |
||||
icon: 'activesessions', |
||||
title: 'Active Sessions', |
||||
subtitle: '3 devices', |
||||
clickable: true |
||||
}); |
||||
|
||||
container.append(blockedUsersRow.container, twoFactorRow.container, activeSessionRow.container); |
||||
} |
||||
|
||||
{ |
||||
const container = section('Privacy'); |
||||
|
||||
const rowsByKeys: Partial<{ |
||||
[key in InputPrivacyKey['_']]: Row |
||||
}> = {}; |
||||
|
||||
const numberVisibilityRow = rowsByKeys['inputPrivacyKeyPhoneNumber'] = new Row({ |
||||
title: 'Who can see my phone number?', |
||||
subtitle: 'My Contacts', |
||||
navigationTab: new AppPrivacyPhoneNumberTab(this.slider) |
||||
}); |
||||
|
||||
const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({ |
||||
title: 'Who can see your Last Seen time?', |
||||
subtitle: 'Everybody', |
||||
clickable: true |
||||
}); |
||||
|
||||
const photoVisibilityRow = rowsByKeys['inputPrivacyKeyProfilePhoto'] = new Row({ |
||||
title: 'Who can see my profile photo?', |
||||
subtitle: 'Everybody', |
||||
clickable: true |
||||
}); |
||||
|
||||
const linkAccountRow = rowsByKeys['inputPrivacyKeyForwards'] = new Row({ |
||||
title: 'Who can add a link to my account when forwarding my messages?', |
||||
subtitle: 'Everybody', |
||||
clickable: true |
||||
}); |
||||
|
||||
const groupChatsAddRow = rowsByKeys['inputPrivacyKeyChatInvite'] = new Row({ |
||||
title: 'Who can add me to group chats?', |
||||
subtitle: 'Everybody', |
||||
clickable: true |
||||
}); |
||||
|
||||
for(const key in rowsByKeys) { |
||||
const row = rowsByKeys[key as keyof typeof rowsByKeys]; |
||||
appPrivacyManager.getPrivacy(key as keyof typeof rowsByKeys).then(rules => { |
||||
const details = appPrivacyManager.getPrivacyRulesDetails(rules); |
||||
const type = details.type === 2 ? 'Everybody' : (details.type === 1 ? 'My Contacts' : 'Nobody'); |
||||
const disallowLength = details.disallowLengths.users + details.disallowLengths.chats; |
||||
const allowLength = details.allowLengths.users + details.allowLengths.chats; |
||||
const str = type + (disallowLength || allowLength ? ` (${[-disallowLength, allowLength ? '+' + allowLength : 0].filter(Boolean).join(', ')})` : ''); |
||||
row.subtitle.innerHTML = str; |
||||
}); |
||||
} |
||||
|
||||
container.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container, linkAccountRow.container, groupChatsAddRow.container); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config"; |
||||
import { InputPrivacyKey, PrivacyRule } from "../../layer"; |
||||
import apiManager from "../mtproto/mtprotoworker"; |
||||
import appChatsManager from "./appChatsManager"; |
||||
import appUsersManager from "./appUsersManager"; |
||||
|
||||
export class AppPrivacyManager { |
||||
constructor() { |
||||
|
||||
} |
||||
|
||||
public getPrivacy(inputKey: InputPrivacyKey['_']) { |
||||
return apiManager.invokeApi('account.getPrivacy', { |
||||
key: { |
||||
_: inputKey |
||||
} |
||||
}).then(privacyRules => { |
||||
appUsersManager.saveApiUsers(privacyRules.users); |
||||
appChatsManager.saveApiChats(privacyRules.chats); |
||||
|
||||
console.log('privacy rules', inputKey, privacyRules, privacyRules.rules); |
||||
|
||||
return privacyRules.rules; |
||||
}); |
||||
} |
||||
|
||||
public getPrivacyRulesDetails(rules: PrivacyRule[]) { |
||||
const types: number[] = []; |
||||
|
||||
let allowLengths = {users: 0, chats: 0}, disallowLengths = {users: 0, chats: 0}; |
||||
rules.forEach(rule => { |
||||
switch(rule._) { |
||||
case 'privacyValueAllowAll': |
||||
types.push(2); |
||||
break; |
||||
case 'privacyValueDisallowAll': |
||||
types.push(0); |
||||
break; |
||||
case 'privacyValueAllowContacts': |
||||
types.push(1); |
||||
break; |
||||
/* case 'privacyValueDisallowContacts': |
||||
types.push('Except My Contacts'); |
||||
break; */ |
||||
case 'privacyValueAllowChatParticipants': |
||||
allowLengths.chats += rule.chats.length; |
||||
break; |
||||
case 'privacyValueAllowUsers': |
||||
allowLengths.users += rule.users.length; |
||||
break; |
||||
case 'privacyValueDisallowChatParticipants': |
||||
disallowLengths.chats += rule.chats.length; |
||||
break; |
||||
case 'privacyValueDisallowUsers': |
||||
disallowLengths.users += rule.users.length; |
||||
break; |
||||
} |
||||
}); |
||||
|
||||
return {type: types[0], disallowLengths, allowLengths}; |
||||
} |
||||
} |
||||
|
||||
const appPrivacyManager = new AppPrivacyManager(); |
||||
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appPrivacyManager = appPrivacyManager); |
||||
export default appPrivacyManager; |
Loading…
Reference in new issue