Advertisement
flicker999

dfg

Mar 7th, 2019
623
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 58.57 KB | None | 0 0
  1. local GUI = require("GUI")
  2. local screen = require("Screen")
  3. local filesystem = require("Filesystem")
  4. local color = require("Color")
  5. local image = require("Image")
  6. local internet = require("Internet")
  7. local json = require("JSON")
  8. local color = require("Color")
  9. local paths = require("Paths")
  10. local system = require("System")
  11. local text = require("Text")
  12. local number = require("Number")
  13.  
  14. --------------------------------------------------------------------------------
  15.  
  16. local VKAPIVersion = "5.85"
  17.  
  18. local config = {
  19. avatars = {
  20. [7799889] = 0x2D2D2D,
  21. },
  22. loadCountConversations = 10,
  23. loadCountMessages = 10,
  24. loadCountNews = 10,
  25. scrollSpeed = 2,
  26. addMessagePostfix = true,
  27. updateContentTrigger = 0.2,
  28. loadCountWall = 10,
  29. loadCountFriends = 10,
  30. loadCountDocs = 10,
  31. maximumPreviewFileSize = 4096,
  32. style = "Default.lua",
  33. }
  34.  
  35. local scriptDirectory = filesystem.path(system.getCurrentScript())
  36. local applicationDataPath = paths.user.applicationData .. "VK/"
  37. local configPath = applicationDataPath .. "Config5.cfg"
  38. local imageCachePath = applicationDataPath .. "Cache/"
  39. local iconsPath = scriptDirectory .. "Icons/"
  40. local stylesPath = scriptDirectory .. "Styles/"
  41.  
  42. --------------------------------------------------------------------------------
  43.  
  44. local currentAccessToken, currentPeerID
  45. local showUserProfile, showConversations
  46. local lastPizda
  47. local style
  48.  
  49. local function saveConfig()
  50. filesystem.writeTable(configPath, config)
  51. end
  52.  
  53. local function loadStyle()
  54. style = filesystem.readTable(stylesPath .. config.style)
  55. end
  56.  
  57. if filesystem.exists(configPath) then
  58. config = filesystem.readTable(configPath)
  59. end
  60.  
  61. local localization = system.getLocalization(scriptDirectory .. "Localizations/")
  62.  
  63. loadStyle()
  64.  
  65. local list, icons = filesystem.list(iconsPath), {}
  66. for i = 1, #list do
  67. icons[unicode.lower(filesystem.hideExtension(list[i]))] = image.load(iconsPath .. list[i])
  68. end
  69.  
  70. --------------------------------------------------------------------------------
  71.  
  72.  
  73. local workspace, window = system.addWindow(GUI.filledWindow(1, 1, 100, 26, 0x0))
  74.  
  75. local leftPanel = window:addChild(GUI.panel(1, 1, 1, 1, 0x0))
  76. local leftLayout = window:addChild(GUI.layout(1, 3, 1, 1, 1, 1))
  77. leftLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  78. leftLayout:setSpacing(1, 1, 1)
  79. leftLayout:setMargin(1, 1, 0, 1)
  80.  
  81. local progressIndicator = window:addChild(GUI.progressIndicator(1, 1, 0x0, 0x0, 0x0))
  82.  
  83. local contentContainer = window:addChild(GUI.container(1, 1, 1, 1))
  84.  
  85. local function log(...)
  86. local file = filesystem.open("/url.log", "a")
  87. file:write(...)
  88. file:write("\n\n")
  89. file:close()
  90. end
  91.  
  92. local function request(url, postData, headers)
  93. progressIndicator.active = true
  94. workspace:draw()
  95.  
  96. -- log("REQUEST URL: ", url)
  97.  
  98. headers = headers or {}
  99. headers["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0"
  100.  
  101. local data = ""
  102. local success, reason = internet.rawRequest(
  103. url,
  104. postData,
  105. headers,
  106. function(chunk)
  107. data = data .. chunk
  108.  
  109. progressIndicator:roll()
  110. workspace:draw()
  111. end,
  112. math.huge
  113. )
  114.  
  115. if success then
  116. data = json.decode(data)
  117. progressIndicator.active = false
  118. workspace:draw()
  119.  
  120. return data
  121. else
  122. GUI.alert("Failed to perform internet request: " .. tostring(reason))
  123. end
  124. end
  125.  
  126. local function responseRequest(...)
  127. local result = request(...)
  128. if result then
  129. if result.response then
  130. return result.response
  131. else
  132. GUI.alert("API request was successfult, but response field is missing, shit saved to /url.log")
  133. -- log("MISSING RESPONSE: ", text.serialize(result, true))
  134. end
  135. end
  136. end
  137.  
  138. local function methodRequest(data)
  139. return responseRequest("https://api.vk.com/method/" .. data .. "&access_token=" .. currentAccessToken .. "&v=" .. VKAPIVersion)
  140. end
  141.  
  142. local function executeRequest(code)
  143. return methodRequest("execute?code=" .. internet.encode(code))
  144. end
  145.  
  146. local function addPanel(container, color)
  147. return container:addChild(GUI.panel(1, 1, container.width, container.height, color), 1)
  148. end
  149.  
  150. local function fitToLastChild(what, addition)
  151. if what.update then
  152. what:update()
  153. end
  154.  
  155. local endPoint = -math.huge
  156. for i = 1, #what.children do
  157. local child = what.children[i]
  158. if not child.hidden then
  159. endPoint = math.max(endPoint, child.localY + child.height - 1)
  160. end
  161. end
  162.  
  163. what.height = endPoint + addition
  164. end
  165.  
  166. local function truncateEmoji(text)
  167. text = text:gsub("&#%d+;", ":)")
  168. return text
  169. end
  170.  
  171. local function drawSelection(object, backgroundColor, textColor)
  172. screen.drawText(object.x, object.y - 1, backgroundColor, string.rep("⣤", object.width - 1) .. "⣴")
  173. screen.drawText(object.x, object.y + object.height, backgroundColor, string.rep("⠛", object.width - 1) .. "⠻")
  174. screen.drawRectangle(object.x, object.y, object.width, object.height, backgroundColor, textColor, " ")
  175. end
  176.  
  177. local function selectableSelect(object)
  178. for i = 1, #object.parent.children do
  179. object.parent.children[i].selected = object.parent.children[i] == object
  180. end
  181.  
  182. workspace:draw()
  183.  
  184. if object.onTouch then
  185. contentContainer.eventHandler = nil
  186. object.onTouch()
  187. end
  188. end
  189.  
  190. local function selectableEventHandler(workspace, object, e1)
  191. if e1 == "touch" then
  192. object:select()
  193. end
  194. end
  195.  
  196. local function addSelectable(layout, method, height)
  197. local object = layout:addChild(GUI[method](1, 1, layout.width, height))
  198.  
  199. object.eventHandler = selectableEventHandler
  200. object.selected = false
  201. object.select = selectableSelect
  202.  
  203. return object
  204. end
  205.  
  206. local function pizdaDraw(object)
  207. local textColor = style.leftToolbarDefaultForeground
  208. if object.selected then
  209. textColor = style.leftToolbarSelectedForeground
  210. drawSelection(object, style.leftToolbarSelectedBackground, textColor)
  211. end
  212.  
  213. screen.drawText(object.x + 2, math.floor(object.y + object.height / 2), textColor, object.name)
  214. end
  215.  
  216. local maxPizdaLength = 0
  217.  
  218. local function pizdaSelect(object)
  219. lastPizda = function()
  220. object:select()
  221. end
  222.  
  223. selectableSelect(object)
  224. end
  225.  
  226. local function addPizda(name)
  227. local object = addSelectable(leftLayout, "object", 1)
  228.  
  229. object.draw = pizdaDraw
  230. object.name = name
  231. object.select = pizdaSelect
  232. maxPizdaLength = math.max(maxPizdaLength, unicode.len(name))
  233.  
  234. return object
  235. end
  236.  
  237. local function addScrollEventHandler(layout, regularDirection, updater)
  238. layout.eventHandler = function(workspace, layout, e1, e2, e3, e4, e5)
  239. if e1 == "scroll" then
  240. local cell = layout.cells[1][1]
  241.  
  242. if regularDirection then
  243. if e5 > 0 then
  244. cell.verticalMargin = cell.verticalMargin + config.scrollSpeed
  245. if cell.verticalMargin > 1 then
  246. cell.verticalMargin = 1
  247. end
  248. else
  249. cell.verticalMargin = cell.verticalMargin - config.scrollSpeed
  250. local lastChild = layout.children[#layout.children]
  251. if lastChild.localY + lastChild.height - 1 < layout.height * (1 - config.updateContentTrigger) then
  252. updater()
  253. end
  254. end
  255. else
  256. if e5 > 0 then
  257. cell.verticalMargin = cell.verticalMargin - config.scrollSpeed
  258. layout:update()
  259.  
  260. if layout.children[1].localY > layout.height * config.updateContentTrigger then
  261. updater()
  262. end
  263. else
  264. cell.verticalMargin = cell.verticalMargin + config.scrollSpeed
  265. if cell.verticalMargin > 1 then
  266. cell.verticalMargin = 1
  267. end
  268. end
  269. end
  270.  
  271. workspace:draw()
  272. end
  273. end
  274. end
  275.  
  276. local function getAbbreviatedFileSize(size, decimalPlaces)
  277. if size < 1024 then
  278. return number.roundToDecimalPlaces(size, 2) .. " B"
  279. else
  280. local power = math.floor(math.log(size, 1024))
  281. return number.roundToDecimalPlaces(size / 1024 ^ power, decimalPlaces) .. " " .. ({"KB", "MB", "GB", "TB"})[power]
  282. end
  283. end
  284.  
  285. local function capitalize(text)
  286. return unicode.upper(unicode.sub(text, 1, 1)) .. unicode.sub(text, 2, -1)
  287. end
  288.  
  289. local function isPeerChat(id)
  290. return id > 2000000000
  291. end
  292.  
  293. local function isPeerGroup(id)
  294. return id < 0
  295. end
  296.  
  297. local function getEblo(where, id)
  298. for i = 1, #where do
  299. if where[i].id == id then
  300. return where[i]
  301. end
  302. end
  303. end
  304.  
  305. local function getSenderName(profiles, conversations, groups, peerID)
  306. if isPeerChat(peerID) then
  307. return conversations.chat_settings.title
  308. elseif isPeerGroup(peerID) then
  309. return getEblo(groups, -peerID).name
  310. else
  311. local eblo = getEblo(profiles, peerID)
  312. return eblo.first_name .. " " .. eblo.last_name
  313. end
  314. end
  315.  
  316. local function getNameShortcut(name)
  317. local first, second = name:match("([^%s]+)%s(.+)")
  318. if first and second then
  319. return unicode.upper(unicode.sub(first, 1, 1) .. unicode.sub(second, 1, 1))
  320. else
  321. return unicode.upper(unicode.sub(name, 1, 2))
  322. end
  323. end
  324.  
  325. local function getAvatarColors(peerID)
  326. local hue = math.abs(peerID) % 360
  327. return color.HSBToInteger(hue, 0.25, 1), color.HSBToInteger(hue, 1, 0.9)
  328. end
  329.  
  330. local function avatarDraw(object)
  331. screen.drawRectangle(object.x, object.y, object.width, object.height, object.backgroundColor, object.textColor, " ")
  332. screen.drawText(math.floor(object.x + object.width / 2 - unicode.len(object.shortcut) / 2), math.floor(object.y + object.height / 2 - 1), object.textColor, object.shortcut)
  333.  
  334. if object.selected then
  335. screen.drawRectangle(object.x, object.y, object.width, object.height, 0x0, 0x0, " ", 0.5)
  336. end
  337. end
  338.  
  339. local function avatarEventHandler(workspace, object, e1)
  340. if e1 == "touch" then
  341. object.selected = true
  342. workspace:draw()
  343.  
  344. event.sleep(0.2)
  345.  
  346. object.selected = false
  347. showUserProfile(object.peerID)
  348. end
  349. end
  350.  
  351. local function newAvatar(x, y, width, height, name, peerID)
  352. local object = GUI.object(x, y, width, height)
  353.  
  354. object.backgroundColor, object.textColor = getAvatarColors(peerID)
  355. object.draw = avatarDraw
  356. object.shortcut = getNameShortcut(name)
  357. object.peerID = peerID
  358.  
  359. -- Нехуй на группы тыкать, НИРИАЛИЗОВАНО ИЩО
  360. if peerID > 0 then
  361. object.eventHandler = avatarEventHandler
  362. end
  363.  
  364. return object
  365. end
  366.  
  367. local function verticalLineDraw(object)
  368. for i = 1, object.height do
  369. screen.drawText(object.x, object.y + i - 1, object.color, "│")
  370. end
  371. end
  372.  
  373. local function newVerticalLine(x, y, height, color)
  374. local object = GUI.object(x, y, 1, height)
  375.  
  376. object.draw = verticalLineDraw
  377. object.color = color
  378.  
  379. return object
  380. end
  381.  
  382. local function horizontalLineDraw(object)
  383. screen.drawText(object.x, object.y, object.color, string.rep("─", object.width))
  384. end
  385.  
  386. local function newHorizontalLine(x, y, width, color)
  387. local object = GUI.object(x, y, width, 1)
  388.  
  389. object.draw = horizontalLineDraw
  390. object.color = color
  391.  
  392. return object
  393. end
  394.  
  395. local function attachmentDraw(object)
  396. -- screen.drawRectangle(object.x, object.y, object.width, 1, 0x880000, 0xA5A5A5, " ")
  397. local x, y, typeLength = object.x, object.y, unicode.len(object.type)
  398. -- Type
  399. screen.drawText(x, y, object.typeB, "⠰"); x = x + 1
  400. screen.drawRectangle(x, y, typeLength + 2, 1, object.typeB, object.typeT, " "); x = x + 1
  401. screen.drawText(x, y, object.typeT, object.type); x = x + typeLength + 1
  402.  
  403. local textB = object.selected and style.blockAttachmentTextSelectionBackground or object.textB
  404. local textT = object.selected and style.blockAttachmentTextSelectionForeground or object.textT
  405.  
  406. screen.set(x, y, textB, object.typeB, "⠆"); x = x + 1
  407. -- Text
  408. screen.drawRectangle(x, y, object.width - typeLength - 5, 1, textB, textT, " "); x = x + 1
  409. screen.drawText(x, y, textT, text.limit(object.text, object.width - typeLength - 7))
  410. screen.drawText(object.x + object.width - 1, y, textB, "⠆")
  411.  
  412. -- if object.previewText or object.previewPicture then
  413. -- screen.drawRectangle(object.x + 1, object.y + 1, object.width - 2, object.height - 1, 0xE1E1E1, 0x0, " ")
  414.  
  415. -- local centerX, centerY = object.x + object.width / 2, object.y + 1 + object.height / 2
  416. -- if object.previewText then
  417. -- screen.drawText(
  418. -- math.floor(centerX - unicode.len(object.previewText) / 2),
  419. -- object.y + 2,
  420. -- 0x0,
  421. -- object.previewText
  422. -- )
  423. -- else
  424. -- screen.drawImage(
  425. -- math.floor(centerX - image.getWidth(object.previewPicture) / 2),
  426. -- math.floor(centerY - image.getHeight(object.previewPicture) / 2),
  427. -- object.previewPicture
  428. -- )
  429. -- end
  430. -- end
  431. end
  432.  
  433. local function newAttachment(x, y, maxWidth, attachment, typeB, typeT, textB, textT)
  434. local object = GUI.object(x, y, 1, 1)
  435.  
  436. object.typeB = typeB
  437. object.typeT = typeT
  438. object.textB = textB
  439. object.textT = textT
  440.  
  441. object.type = capitalize(localization.attachmentsTypes[attachment.type])
  442.  
  443. if attachment.photo then
  444. local maxIndex, maxWidth = 1, 0
  445. for i = 1, #attachment.photo.sizes do
  446. if maxWidth < attachment.photo.sizes[i].width then
  447. maxIndex, maxWidth = i, attachment.photo.sizes[i].width
  448. end
  449. end
  450.  
  451. object.text = attachment.photo.sizes[maxIndex].width .. " x " .. attachment.photo.sizes[maxIndex].height .. " px"
  452. elseif attachment.video then
  453. object.text = attachment.video.title
  454. elseif attachment.audio then
  455. object.text = attachment.audio.artist .. " - " .. attachment.audio.title
  456. elseif attachment.sticker then
  457. object.text = ":)"
  458. elseif attachment.link then
  459. object.text = #attachment.link.title > 0 and attachment.link.title or attachment.link.url
  460. elseif attachment.doc then
  461. -- if attachment.doc.ext == "pic" then
  462. -- object.type = "OC Image"
  463. -- local cachePath = imageCachePath .. attachment.doc.owner_id .. "_" .. attachment.doc.id .. ".pic"
  464.  
  465. -- if attachment.doc.size <= config.maximumPreviewFileSize then
  466. -- local function try()
  467. -- local picture, reason = image.load(cachePath)
  468. -- if picture then
  469. -- if image.getWidth(picture) <= maxWidth then
  470. -- object.previewPicture = picture
  471. -- object.height = object.height + image.getHeight(picture) - 1
  472. -- else
  473. -- object.previewText = "Image is too big for preview"
  474. -- end
  475. -- else
  476. -- object.previewText = tostring(reason)
  477. -- end
  478. -- end
  479.  
  480. -- if filesystem.exists(cachePath) then
  481. -- try()
  482. -- else
  483. -- local success, reason = internet.download(attachment.doc.url, cachePath)
  484. -- if success then
  485. -- try()
  486. -- else
  487. -- object.previewText = "Failed to download image"
  488. -- end
  489. -- end
  490. -- else
  491. -- object.previewText = "Image file size is too big"
  492. -- end
  493.  
  494. -- object.height = object.height + 3
  495. -- end
  496.  
  497. object.text = attachment.doc.title .. ", " .. getAbbreviatedFileSize(attachment.doc.size)
  498. elseif attachment.gift then
  499. object.text = ":3"
  500. elseif attachment.audio_message then
  501. local length = 30
  502.  
  503. local values, trigger, value, counter, stepper, maxValue = {}, #attachment.audio_message.waveform / length, 0, 0, 0, 0
  504. for i = 1, #attachment.audio_message.waveform do
  505. value = value + attachment.audio_message.waveform[i]
  506.  
  507. if stepper > trigger then
  508. table.insert(values, value / counter)
  509. maxValue = math.max(maxValue, values[#values])
  510.  
  511. value, counter, stepper = 0, 0, stepper - trigger
  512. else
  513. counter, stepper = counter + 1, stepper + 1
  514. end
  515. end
  516.  
  517. local pixels = {"⡀", "⡄", "⡆", "⡇"}
  518.  
  519. object.text = ""
  520. for i = 1, #values do
  521. object.text = object.text .. (pixels[math.ceil(values[i] / maxValue * 4)] or "⡀")
  522. end
  523. else
  524. object.text = "N/A"
  525. end
  526.  
  527. object.width = math.min(maxWidth, unicode.len(object.type) + unicode.len(object.text) + 7)
  528.  
  529. object.draw = attachmentDraw
  530. object.eventHandler = attachmentEventHandler
  531.  
  532. return object
  533. end
  534.  
  535. local function newPost(x, y, width, avatarWidth, senderColor, textColor, dateColor, lineColor, attachmentColorTypeB, attachmentColorTypeF, attachmentColorTextB, attachmentColorTextF, mainMessage, profiles, conversations, groups, senderName, fwdMessagesFieldName, data)
  536. local object = GUI.container(x, y, width, 1)
  537.  
  538. local localX, localY = 1, 1
  539.  
  540. local avatar = object:addChild(newAvatar(localX, localY, avatarWidth, math.floor(avatarWidth / 2), getNameShortcut(senderName), data.from_id or data.source_id))
  541. localX = localX + avatar.width + 1
  542.  
  543. local nameText = object:addChild(GUI.text(localX, localY, senderColor, senderName))
  544. object:addChild(GUI.text(localX + nameText.width + 1, localY, dateColor, os.date("%H:%M", data.date)))
  545.  
  546. localY = localY + 1
  547.  
  548. if #data.text > 0 then
  549. local lines = text.wrap(data.text, width - localX)
  550. object.textBox = object:addChild(GUI.textBox(localX, localY, width - localX, #lines, nil, textColor, lines, 1, 0, 0))
  551. object.textBox.eventHandler = nil
  552. localY = localY + object.textBox.height + 1
  553. else
  554. localY = localY + 1
  555. end
  556.  
  557. local function addAnotherPost(senderName, data)
  558. -- localY = localY + (mainMessage and 0 or 1)
  559.  
  560. local offset = mainMessage and avatarWidth + 2 or 1
  561. local attachment = object:addChild(
  562. newPost(
  563. offset + 2,
  564. localY,
  565. math.max(16, width - 6),
  566. avatarWidth,
  567. senderColor,
  568. textColor,
  569. dateColor,
  570. lineColor,
  571. attachmentColorTypeB,
  572. attachmentColorTypeF,
  573. attachmentColorTextB,
  574. attachmentColorTextF,
  575. false,
  576. profiles,
  577. conversations,
  578. groups,
  579. senderName,
  580. fwdMessagesFieldName,
  581. data
  582. )
  583. )
  584. object:addChild(newVerticalLine(offset, localY, attachment.height, lineColor))
  585.  
  586. localY = localY + attachment.height + 1
  587. end
  588.  
  589. if data.attachments and #data.attachments > 0 then
  590. for i = 1, #data.attachments do
  591. local attachment = data.attachments[i]
  592. if localization.attachmentsTypes[attachment.type] then
  593. if attachment.wall then
  594. addAnotherPost(
  595. attachment.wall.from.name or (attachment.wall.from.first_name .. " " .. attachment.wall.from.last_name),
  596. attachment.wall
  597. )
  598. else
  599. local attachment = object:addChild(newAttachment(localX, localY, object.width - localX, attachment, attachmentColorTypeB, attachmentColorTypeF, attachmentColorTextB, attachmentColorTextF))
  600. localY = localY + attachment.height + 1
  601. end
  602. end
  603. end
  604. end
  605.  
  606. -- fwd_messages
  607. if data[fwdMessagesFieldName] then
  608. for i = 1, #data[fwdMessagesFieldName] do
  609. addAnotherPost(
  610. getSenderName(profiles, conversations, groups, data[fwdMessagesFieldName][i].from_id),
  611. data[fwdMessagesFieldName][i]
  612. )
  613. end
  614. end
  615.  
  616. if data.likes or data.reposts or data.views or data.comments then
  617. local layout = object:addChild(GUI.layout(localX, localY, object.width - localX, 2, 1, 1))
  618. layout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_BOTTOM)
  619. layout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL)
  620. layout:setSpacing(1, 1, 2)
  621.  
  622. local function addStuff(icon, text)
  623. local container = layout:addChild(GUI.container(1, 1, 5 + unicode.len(text), 2))
  624. container:addChild(GUI.image(1, 1, icon))
  625. container:addChild(GUI.text(6, 2, style.counterText, text))
  626. end
  627.  
  628. addStuff(icons.likes, tostring(data.likes and data.likes.count or 0))
  629. addStuff(icons.comments, tostring(data.comments and data.comments.count or 0))
  630. addStuff(icons.reposts, tostring(data.reposts and data.reposts.count or 0))
  631. addStuff(icons.views, tostring(data.views and data.views.count or 0))
  632.  
  633. localY = localY + 3
  634. end
  635.  
  636. object.height = localY - 2
  637.  
  638. -- object:addChild(GUI.panel(1, 1, width, object.height, math.random(0xFFFFFF)), 1)
  639.  
  640. return object
  641. end
  642.  
  643. local function uploadDocument(path)
  644. local fileName = filesystem.name(path)
  645. local uploadServer = methodRequest("docs.getUploadServer?")
  646. if uploadServer then
  647. local boundary = "----WebKitFormBoundaryISgaMqjePLcGZFOx"
  648. local handle = filesystem.open(path, "rb")
  649.  
  650. local data =
  651. "--" .. boundary .. "\r\n" ..
  652. "Content-Disposition: form-data; name=\"file\"; filename=\"" .. fileName .. "\"\r\n" ..
  653. "Content-Type: application/octet-stream\r\n\r\n" ..
  654. handle:read("*a") .. "\r\n" ..
  655. "--" .. boundary .. "--"
  656.  
  657. handle:close()
  658.  
  659. local uploadResult, reason = request(
  660. uploadServer.upload_url,
  661. data,
  662. {
  663. ["Content-Type"] = "multipart/form-data; boundary=" .. boundary,
  664. ["Content-Length"] = #data,
  665. }
  666. )
  667.  
  668. filesystem.writeTable("/test.txt", {
  669. url = uploadServer.upload_url,
  670. data = data,
  671. size = #data,
  672. }, true)
  673.  
  674. if uploadResult then
  675. if uploadResult.file then
  676. return methodRequest("docs.save?file=" .. uploadResult.file .. "&title=" .. fileName)
  677. else
  678. GUI.alert("UPLOAD ALMOST ZAEBIS, BUT NOT FILE", uploadResult)
  679. end
  680. else
  681. GUI.alert("UPLOAD FAIL", reason)
  682. end
  683. end
  684. end
  685.  
  686. local function getHistory(peerID, startMessageID)
  687. return methodRequest("messages.getHistory?extended=1&fields=first_name,last_name,online&count=" .. config.loadCountMessages .. "&peer_id=" .. peerID .. (startMessageID and "&offset=1" or "") .. (startMessageID and ("&start_message_id=" .. startMessageID) or ""))
  688. end
  689.  
  690. local function showHistory(container, peerID)
  691. local messagesHistory = getHistory(peerID, nil)
  692. if messagesHistory then
  693. container:removeChildren()
  694.  
  695. local inputLayout = container:addChild(GUI.layout(1, container.height - 2, container.width, 3, 1, 1))
  696. inputLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  697. inputLayout:setSpacing(1, 1, 0)
  698. inputLayout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL)
  699.  
  700. local attachButton = inputLayout:addChild(GUI.adaptiveButton(1, 1, 2, 1, style.messageButtonDefaultBackground, style.messageButtonDefaultForeground, style.messageButtonPressedBackground, style.messageButtonPressedForeground, "+"))
  701. attachButton.switchMode = true
  702. local sendButton = inputLayout:addChild(GUI.adaptiveButton(1, 1, 2, 1, style.messageButtonDefaultBackground, style.messageButtonDefaultForeground, style.messageButtonPressedBackground, style.messageButtonPressedForeground, localization.send))
  703. local input = inputLayout:addChild(GUI.input(1, 1, inputLayout.width - sendButton.width - attachButton.width, 3, style.messageInputBackground, style.messageInputForeground, style.messageInputPlaceholder, style.messageInputBackground, style.messageInputForeground, "", localization.typeMessageHere), 2)
  704.  
  705. local layout = container:addChild(GUI.layout(2, 1, container.width - 2, container.height - input.height, 1, 1))
  706. layout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_BOTTOM)
  707. layout:setMargin(1, 1, 0, 1)
  708.  
  709. local function addFromHistory(history)
  710. for i = 1, #history.items do
  711. local post = layout:addChild(
  712. newPost(
  713. 2,
  714. y,
  715. container.width - 2,
  716. 4,
  717. style.messageSelectedTitle,
  718. style.messageSelectedText,
  719. style.messageSelectedDate,
  720. style.messageSelectedLine,
  721. style.messageAttachmentTypeBackground,
  722. style.messageAttachmentTypeForeground,
  723. style.messageAttachmentTextBackground,
  724. style.messageAttachmentTextForeground,
  725. true,
  726. history.profiles,
  727. history.conversations,
  728. history.groups,
  729. getSenderName(
  730. history.profiles,
  731. history.conversations,
  732. history.groups,
  733. history.items[i].from_id
  734. ),
  735. "fwd_messages",
  736. history.items[i]
  737. ), 1
  738. )
  739.  
  740. post.id = history.items[i].id
  741. end
  742. end
  743.  
  744. addFromHistory(messagesHistory)
  745.  
  746. addScrollEventHandler(layout, false, function()
  747. local newMessagesHistory = getHistory(peerID, layout.children[1].id)
  748. if newMessagesHistory then
  749. addFromHistory(newMessagesHistory)
  750. end
  751. end)
  752.  
  753. local attachedPath
  754. attachButton.onTouch = function()
  755. if attachedPath then
  756. attachedPath = nil
  757. else
  758. local filesystemDialog = GUI.addFilesystemDialog(window, true, 45, window.height - 5, "Open", "Cancel", "File name", "/")
  759. filesystemDialog:setMode(GUI.IO_MODE_OPEN, GUI.IO_MODE_FILE)
  760. filesystemDialog.onSubmit = function(path)
  761. attachedPath = path
  762. end
  763. filesystemDialog:show()
  764. end
  765. end
  766.  
  767. sendButton.onTouch = function()
  768. if #input.text > 0 then
  769. local attachment
  770. if attachedPath then
  771. local saveResult = uploadDocument(attachedPath)
  772. if saveResult then
  773. attachment = "&attachment=doc" .. saveResult[1].owner_id .. "_" .. saveResult[1].id
  774. end
  775.  
  776. attachedPath = nil
  777. end
  778.  
  779. local sendResult = methodRequest("messages.send?peer_id=" .. peerID .. (attachment or "") .. (#input.text > 0 and ("&message=" .. internet.encode(input.text)) or ""))
  780. if sendResult then
  781. showHistory(container, peerID)
  782. end
  783. end
  784. end
  785.  
  786. workspace:draw()
  787. end
  788. end
  789.  
  790. local function usersRequest(ids, nameCase, fields)
  791. return methodRequest("users.get?name_case=" .. nameCase .. "&user_ids=" .. ids .. (fields and "&fields=" .. fields or ""))
  792. end
  793.  
  794. local function friendsRequest(online, peerID, order, offset, count, fields)
  795. return methodRequest("friends.get" .. (online and "Online" or "") .. "?name_case=Nom&user_id=" .. peerID .. "&order=" .. order .. (offset and "&offset=" .. offset or "") .. (count and "&count=" .. count or "") .. (fields and "&fields=" .. fields or ""))
  796. end
  797.  
  798. local function wallRequest(peerID, offset, filter)
  799. return methodRequest("wall.get?extended=1&fields=first_name,last_name&owner_id=" .. peerID .. "&offset=" .. offset .. "&count=" .. config.loadCountWall .. "&filter=" .. filter)
  800. end
  801.  
  802. showUserProfile = function(peerID)
  803. local friendsDisplayColumns, friendsDisplayRows = 3, 2
  804. local friendsDisplayCount = friendsDisplayColumns * friendsDisplayRows
  805. local friendsNameLimit = 6
  806.  
  807. local result = executeRequest([[
  808. var me=API.users.get({"user_ids":]] .. peerID .. [[,"fields":"activities,education,tv,status,sex,schools,relation,quotes,personal,occupation,connections,counters,contacts,verified,city,country,site,last_seen,online,bdate,books,movies,music,games,universities,interests,home_town,relatives,friend_status","name_case":"Nom"})[0];
  809. var args={"user_id":me.id,"order" :"random","count":]] .. friendsDisplayCount .. [[,"target_uid":]] .. peerID .. [[};
  810. var AFR=API.friends.get(args);
  811. args.count=null;
  812. var OFR=API.friends.getOnline(args);
  813. var MFR=API.friends.getMutual(args);
  814. var OFC=OFR.length;
  815. var MFC=MFR.length;
  816. OFR=OFR.slice(0,]] .. friendsDisplayCount .. [[);
  817. MFR=MFR.slice(0,]] .. friendsDisplayCount .. [[);
  818. var S="";
  819. var i=0;
  820. while (i < AFR.items.length) {
  821. S=S+AFR.items[i]+",";
  822. i=i+1;
  823. }
  824. i=0;
  825. while (i<OFR.length) {
  826. S=S+OFR[i]+",";
  827. i=i+1;
  828. }
  829. i=0;
  830. while (i < MFR.length) {
  831. S=S+MFR[i]+",";
  832. i=i+1;
  833. }
  834. var SFI=API.users.get({"user_ids":S.substr(0,S.length - 1),"fields":"first_name"});
  835. var AFI={};
  836. var OFI={};
  837. var MFI={};
  838. var j;
  839. i=0;
  840. while (i < AFR.items.length) {
  841. j=0;
  842. while (j < SFI.length) {
  843. if (AFR.items[i] == SFI[j].id) {
  844. AFI.push(SFI[j]);
  845. j=SFI.length;
  846. }
  847. j=j+1;
  848. }
  849. i=i+1;
  850. }
  851. i=0;
  852. while (i < OFR.length) {
  853. j=0;
  854. while (j < SFI.length) {
  855. if (OFR[i] == SFI[j].id) {
  856. OFI.push(SFI[j]);
  857. j=SFI.length;
  858. }
  859. j=j+1;
  860. }
  861. i=i+1;
  862. }
  863. i=0;
  864. while (i < MFR.length) {
  865. j=0;
  866. while (j < SFI.length) {
  867. if (MFR[i] == SFI[j].id) {
  868. MFI.push(SFI[j]);
  869. j=SFI.length;
  870. }
  871. j=j+1;
  872. }
  873. i=i+1;
  874. }
  875. return {
  876. "user":me,
  877. "all_friends":AFI,
  878. "online_friends":OFI,
  879. "mutual_friends":MFI,
  880. "all_friends_count":AFR.count,
  881. "online_friends_count":OFC,
  882. "mutual_friends_count":MFC
  883. };
  884. ]])
  885.  
  886. if result then
  887. local wall = wallRequest(peerID, 0, "all")
  888. if wall then
  889. local user = result.user
  890. local fullName = user.first_name .. " " .. user.last_name
  891. local profileKeys = localization.profileKeys
  892.  
  893. contentContainer:removeChildren()
  894.  
  895. local userContainer = contentContainer:addChild(GUI.container(1, 1, contentContainer.width, 1))
  896.  
  897. -- Авочка
  898. local leftLayout = userContainer:addChild(GUI.layout(3, 2, 24, 1, 1, 1))
  899. leftLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  900.  
  901. local avatarContainer = leftLayout:addChild(GUI.container(1, 1, leftLayout.width, 1))
  902. local avatar = avatarContainer:addChild(newAvatar(3, 2, avatarContainer.width - 4, math.floor((avatarContainer.width - 4) / 2), getNameShortcut(fullName), user.id))
  903.  
  904. if peerID ~= currentPeerID then
  905. local messageButton = avatarContainer:addChild(GUI.roundedButton(3, avatar.localY + avatar.height + 1, avatar.width, 1, style.blockButtonDefaultBackground, style.blockButtonDefaultForeground, style.blockButtonPressedBackground, style.blockButtonPressedForeground, localization.message))
  906. messageButton.onTouch = function()
  907. showConversations(peerID)
  908. end
  909. end
  910.  
  911. fitToLastChild(avatarContainer, 1)
  912. addPanel(avatarContainer, style.blockBackground)
  913.  
  914. -- Список друзяшек
  915. local function addFriendsList(title, titleCount, list)
  916. if #list > 0 then
  917. local rowsCount = math.min(math.ceil(#list / friendsDisplayColumns), friendsDisplayRows)
  918.  
  919. local container = leftLayout:addChild(GUI.container(1, 1, leftLayout.width, 3 + rowsCount * 5))
  920.  
  921. addPanel(container, style.blockBackground)
  922. title = container:addChild(GUI.text(3, 2, style.blockTitle, title))
  923. container:addChild(GUI.text(title.localX + title.width + 1, 2, style.blockValue, tostring(titleCount)))
  924.  
  925. local layout = container:addChild(GUI.layout(1, 4, container.width, container.height - 3, friendsDisplayColumns, rowsCount))
  926.  
  927. local index = 1
  928. for row = 1, rowsCount do
  929. for column = 1, friendsDisplayColumns do
  930. if list[index] then
  931. layout.defaultColumn, layout.defaultRow = column, row
  932.  
  933. local eblo = list[index]
  934. layout:addChild(newAvatar(1, 1, 4, 2, getNameShortcut(eblo.first_name .. " " .. eblo.last_name), eblo.id))
  935. layout:addChild(GUI.text(1, 4, 0xA5A5A5, text.limit(eblo.first_name, friendsNameLimit)))
  936.  
  937. index = index + 1
  938. else
  939. break
  940. end
  941. end
  942. end
  943. end
  944. end
  945.  
  946. if peerID ~= currentPeerID then
  947. addFriendsList(localization.friendsMutual, result.mutual_friends_count, result.mutual_friends)
  948. end
  949. addFriendsList(localization.friends, result.all_friends_count, result.all_friends)
  950. addFriendsList(localization.friendsOnline, result.online_friends_count, result.online_friends)
  951.  
  952. -- Инфа о юзвере
  953. local rightLayout = userContainer:addChild(GUI.layout(leftLayout.localX + leftLayout.width + 2, 2, userContainer.width - leftLayout.width - 6, 1, 1, 1))
  954. rightLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  955.  
  956. local infoContainer = rightLayout:addChild(GUI.container(1, 1, rightLayout.width, 1))
  957. local infoPanel = addPanel(infoContainer, style.blockBackground)
  958. local infoLayout = infoContainer:addChild(GUI.layout(infoPanel.localX + 2, infoPanel.localY + 1, infoPanel.width - 4, 1, 1, 1))
  959. infoLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  960. infoLayout:setSpacing(1, 1, 0)
  961.  
  962. local layoutToAdd = infoLayout
  963.  
  964. local function addTitle(text)
  965. local container = layoutToAdd:addChild(GUI.container(1, 1, layoutToAdd.width, 3))
  966.  
  967. if text then
  968. text = container:addChild(GUI.text(1, 2, style.blockTitle, text))
  969. container:addChild(newHorizontalLine(text.width + 2, 2, container.width - text.width - 1, style.blockLine))
  970. else
  971. container:addChild(newHorizontalLine(1, 2, container.width, style.blockLine))
  972. end
  973. end
  974.  
  975. local maxProfileKeyLength = 0
  976. for key, value in pairs(profileKeys) do
  977. maxProfileKeyLength = math.max(maxProfileKeyLength, unicode.len(value))
  978. end
  979. maxProfileKeyLength = maxProfileKeyLength + 4
  980.  
  981. local function addKeyAndValue(key, value)
  982. local container = layoutToAdd:addChild(GUI.container(1, 1, layoutToAdd.width, 1))
  983. container:addChild(GUI.text(1, 1, style.blockKey, key .. ": "))
  984.  
  985. local width = container.width - maxProfileKeyLength
  986. local lines = text.wrap(value, width)
  987. container:addChild(GUI.textBox(maxProfileKeyLength, 1, width, #lines, nil, style.blockValue, lines, 1)).eventHandler = nil
  988.  
  989. container.height = #lines
  990. end
  991.  
  992. local function isTypeValid(what)
  993. local whatType = type(what)
  994. return what and (whatType == "string" and #what > 0 or whatType == "number" and what ~= 0)
  995. end
  996.  
  997. local function anyExists(...)
  998. local args = {...}
  999. for i = 1, #args do
  1000. if isTypeValid(args[i]) then
  1001. return true
  1002. end
  1003. end
  1004. end
  1005.  
  1006. local function addIfExists(what, ...)
  1007. if isTypeValid(what) then
  1008. addKeyAndValue(...)
  1009. end
  1010. end
  1011.  
  1012. infoLayout:addChild(GUI.text(1, 1, style.blockTitle, fullName))
  1013.  
  1014. if user.status and #user.status > 0 then
  1015. local statusButton = infoLayout:addChild(GUI.adaptiveButton(1, 1, 0, 0, nil, style.blockValue, nil, 0x0, user.status_audio and ("* " .. user.status_audio.artist .. " - " .. user.status_audio.title) or user.status))
  1016. end
  1017.  
  1018. addTitle()
  1019.  
  1020. if user.bdate then
  1021. local cyka = {}
  1022. for part in user.bdate:gmatch("%d+") do
  1023. table.insert(cyka, part)
  1024. end
  1025. addKeyAndValue(profileKeys.birthday, cyka[1] .. " " .. localization.months[tonumber(cyka[2])] .. (cyka[3] and " " .. cyka[3] or ""))
  1026. end
  1027.  
  1028. if user.city then
  1029. addKeyAndValue(profileKeys.city, user.city.title == "Москва" and "Массква" or user.city.title)
  1030. end
  1031.  
  1032. addIfExists(user.relation, profileKeys.relation, localization.relationStatuses[user.sex > 0 and user.sex or 1][user.relation])
  1033.  
  1034. if user.occupation then
  1035. addKeyAndValue(profileKeys.occupation, user.occupation.name)
  1036. end
  1037.  
  1038. if user.university_name and #user.university_name > 0 then
  1039. addKeyAndValue(profileKeys.education, user.university_name .. "'" .. tostring(user.graduation):sub(-2, -1))
  1040. end
  1041.  
  1042. addIfExists(user.site, profileKeys.site, user.site)
  1043.  
  1044. -- Вот тута начинается дополнительная инфа
  1045. local expandButton = infoLayout:addChild(GUI.button(1, 1, infoLayout.width, 2, nil, style.blockTextButton, nil, 0x0, ""))
  1046.  
  1047. local additionalLayout = infoLayout:addChild(GUI.layout(1, 1, infoLayout.width, 1, 1, 1))
  1048. additionalLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  1049. additionalLayout:setSpacing(1, 1, 0)
  1050. additionalLayout.hidden = true
  1051.  
  1052. layoutToAdd = additionalLayout
  1053.  
  1054. -- Основная инфа
  1055. if anyExists(user.home_town, user.personal and user.personal.langs) then
  1056. addTitle(localization.profileTitleMainInformation)
  1057.  
  1058. addIfExists(user.home_town, profileKeys.homeCity, user.home_town)
  1059.  
  1060. if user.personal and user.personal.langs then
  1061. addKeyAndValue(profileKeys.languages, table.concat(user.personal.langs, ", "))
  1062. end
  1063. end
  1064.  
  1065. -- Контакты
  1066. if anyExists(user.mobile_phone, user.home_phone, user.skype, user.instagram, user.facebook) then
  1067. addTitle(localization.profileTitleContacts)
  1068.  
  1069. addIfExists(user.mobile_phone, profileKeys.mobilePhone, user.mobile_phone)
  1070. addIfExists(user.home_phone, profileKeys.homePhone, user.home_phone)
  1071. addIfExists(user.skype, "Skype", user.skype)
  1072. addIfExists(user.instagram, "Instagram", user.instagram)
  1073. addIfExists(user.facebook, "Facebook", user.facebook)
  1074. end
  1075.  
  1076. if user.personal and anyExists(user.personal.political, user.personal.religon, user.personal.life_main, user.personal.people_main, user.personal.smoking, user.personal.alcohol, user.personal.inspired_by) then
  1077. addTitle(localization.profileTitlePersonal)
  1078.  
  1079. addIfExists(user.personal.political, profileKeys.political, localization.personalPoliticalTypes[user.personal.political])
  1080.  
  1081. addIfExists(user.personal.religon, profileKeys.religion, user.personal.religon)
  1082.  
  1083. addIfExists(user.personal.life_main, profileKeys.lifeMain, localization.personalLifeMainTypes[user.personal.life_main])
  1084.  
  1085. addIfExists(user.personal.people_main, profileKeys.peopleMain, localization.personalPeopleMainTypes[user.personal.people_main])
  1086.  
  1087. addIfExists(user.personal.smoking, profileKeys.smoking, localization.personalBlyadTypes[user.personal.smoking])
  1088.  
  1089. addIfExists(user.personal.alcohol, profileKeys.alcohol, localization.personalBlyadTypes[user.personal.alcohol])
  1090.  
  1091. addIfExists(user.personal.inspired_by, profileKeys.inspiredBy, user.personal.inspired_by)
  1092. end
  1093.  
  1094. if anyExists(user.activities, user.interests, user.music, user.movies, user.tv, user.games, user.books, user.quotes) then
  1095. addTitle(localization.profileTitleAdditions)
  1096.  
  1097. addIfExists(user.activities, profileKeys.activities, user.activities)
  1098. addIfExists(user.interests, profileKeys.interests, user.interests)
  1099. addIfExists(user.music, profileKeys.music, user.music)
  1100. addIfExists(user.movies, profileKeys.movies, user.movies)
  1101. addIfExists(user.tv, profileKeys.tv, user.tv)
  1102. addIfExists(user.games, profileKeys.games, user.games)
  1103. addIfExists(user.books, profileKeys.books, user.books)
  1104. addIfExists(user.quotes, profileKeys.quotes, user.quotes)
  1105. end
  1106.  
  1107. -- И снова добавляем в основной лейаут
  1108. layoutToAdd = infoLayout
  1109.  
  1110. addTitle()
  1111.  
  1112. local statsLayout = layoutToAdd:addChild(GUI.layout(1, 1, layoutToAdd.width, 2, 1, 1))
  1113. statsLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP)
  1114. statsLayout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL)
  1115. statsLayout:setSpacing(1, 1, 2)
  1116.  
  1117. local function counterDraw(object)
  1118. local centerX = object.x + object.width / 2
  1119. screen.drawText(math.floor(centerX - object.countLength / 2), object.y, style.blockTitle, object.count)
  1120. screen.drawText(math.floor(centerX - object.descriptionLength / 2), object.y + 1, style.blockValue, object.description)
  1121. end
  1122.  
  1123. for i = 1, #localization.profileCounters do
  1124. local count = user.counters[localization.profileCounters[i].field]
  1125. if count then
  1126. local object = GUI.object(1, 1, 1, 2)
  1127.  
  1128. object.count = tostring(count)
  1129. object.description = localization.profileCounters[i].description
  1130. object.countLength = unicode.len(object.count)
  1131. object.descriptionLength = unicode.len(object.description)
  1132. object.width = math.max(object.countLength, object.descriptionLength)
  1133. object.draw = counterDraw
  1134.  
  1135. statsLayout:addChild(object)
  1136. end
  1137. end
  1138.  
  1139. -- Стена
  1140. local wallLayout = rightLayout:addChild(GUI.layout(1, 1, rightLayout.width, 1, 1, 1))
  1141. wallLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  1142.  
  1143. for i = 1, #wall.items do
  1144. local item = wall.items[i]
  1145. local post = newPost(
  1146. 3,
  1147. 2,
  1148. rightLayout.width - 4,
  1149. 4,
  1150. style.blockTitle,
  1151. style.blockText,
  1152. style.blockDate,
  1153. style.blockLine,
  1154. style.blockAttachmentTypeBackground,
  1155. style.blockAttachmentTypeForeground,
  1156. style.blockAttachmentTextBackground,
  1157. style.blockAttachmentTextForeground,
  1158. true,
  1159. wall.profiles,
  1160. wall.conversations,
  1161. wall.groups,
  1162. getSenderName(wall.profiles, wall.conversations, wall.groups, item.from_id),
  1163. "copy_history",
  1164. item
  1165. )
  1166.  
  1167. local container = wallLayout:addChild(GUI.container(1, 1, rightLayout.width, post.height + 2))
  1168. addPanel(container, style.blockBackground)
  1169. container:addChild(post)
  1170. end
  1171.  
  1172. fitToLastChild(wallLayout, 0)
  1173.  
  1174. local function update()
  1175. -- Фиттим дополнительный лейаут
  1176. fitToLastChild(additionalLayout, 0)
  1177. -- Фиттим лейаут с инфой
  1178. fitToLastChild(infoLayout, 0)
  1179. -- Подгоняем контейнер под него
  1180. infoContainer.height = infoLayout.height + 2
  1181. infoPanel.height = infoContainer.height
  1182. -- Фиттим лево-правые лейауты
  1183. fitToLastChild(leftLayout, 1)
  1184. fitToLastChild(rightLayout, 1)
  1185. -- Фиттим весь юзер-контейнер с авой, друганами и всем дерьмом
  1186. fitToLastChild(userContainer, 0)
  1187. -- Ой, кнопочка!
  1188. expandButton.text = additionalLayout.hidden and localization.profileShowAdditional or localization.profileHideAdditional
  1189. end
  1190.  
  1191. update()
  1192.  
  1193. expandButton.onTouch = function()
  1194. additionalLayout.hidden = not additionalLayout.hidden
  1195. update()
  1196. end
  1197.  
  1198. contentContainer.eventHandler = function(workspace, contentContainer, e1, e2, e3, e4, e5)
  1199. if e1 == "scroll" then
  1200. userContainer.localY = userContainer.localY + (e5 > 0 and 1 or -1) * config.scrollSpeed
  1201.  
  1202. if userContainer.localY + userContainer.height - 1 < contentContainer.height then
  1203. userContainer.localY = contentContainer.height - userContainer.height
  1204. end
  1205.  
  1206. if userContainer.localY > 1 then
  1207. userContainer.localY = 1
  1208. end
  1209.  
  1210. workspace:draw()
  1211. end
  1212. end
  1213. end
  1214. end
  1215. end
  1216.  
  1217. local profileSelectable = addPizda(localization.profile)
  1218. profileSelectable.onTouch = function()
  1219. showUserProfile(currentPeerID)
  1220.  
  1221. -- Яша
  1222. -- showUserProfile(60991376)
  1223.  
  1224. -- Яна
  1225. -- showUserProfile(155326634)
  1226.  
  1227. -- Крутой
  1228. -- showUserProfile(21321257)
  1229. end
  1230.  
  1231. local function showFriends(peerID)
  1232. local offset = 0
  1233.  
  1234. local function getFriends()
  1235. local result = executeRequest([[
  1236. var friends = API.friends.get({"offset":]] .. offset .. [[,"count":]] .. config.loadCountFriends .. [[,"order": "hints","fields":"first_name,last_name,occupation"});
  1237. var lists = API.friends.getLists();
  1238. return {
  1239. "friends": friends.items,
  1240. "lists": lists.items,
  1241. "friends_count": friends.count
  1242. };
  1243. ]])
  1244.  
  1245. if result then
  1246. -- Удобнее!
  1247. local newLists = {}
  1248.  
  1249. for i = 1, #result.lists do
  1250. newLists[result.lists[i].id] = result.lists[i].name
  1251. end
  1252.  
  1253. result.lists = newLists
  1254.  
  1255. return result
  1256. end
  1257. end
  1258.  
  1259. local friends = getFriends()
  1260. if friends then
  1261. contentContainer:removeChildren()
  1262.  
  1263. local layout = contentContainer:addChild(GUI.layout(3, 1, contentContainer.width - 4, contentContainer.height, 1, 1))
  1264. layout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  1265. layout:setMargin(1, 1, 0, 1)
  1266.  
  1267. local function addFromList(result)
  1268. for i = 1, #result.friends do
  1269. local friend = result.friends[i]
  1270. local fullName = friend.first_name .. " " .. friend.last_name
  1271. local container = layout:addChild(GUI.container(1, 1, layout.width, 1))
  1272.  
  1273. local avatar = container:addChild(newAvatar(3, 2, 8, 4, getNameShortcut(fullName), friend.id))
  1274.  
  1275. local startX = avatar.localX + avatar.width + 2
  1276. local x, y = startX, avatar.localY
  1277.  
  1278. container:addChild(GUI.text(startX, y, style.blockTitle, fullName)); y = y + 1
  1279. if friend.occupation then
  1280. container:addChild(GUI.text(startX, y, style.blockValue, friend.occupation.name)); y = y + 1
  1281. end
  1282. y = y + 1
  1283.  
  1284. if friend.lists then
  1285. local offset, space = 1, 2
  1286.  
  1287. for j = 1, #friend.lists do
  1288. local text = result.lists[friend.lists[j]] or "N/A"
  1289.  
  1290. if x + unicode.len(text) + offset * 2 >= container.width then
  1291. x, y = startX, y + 2
  1292. end
  1293.  
  1294. local button = container:addChild(GUI.adaptiveRoundedButton(x, y, offset, 0, style.blockButtonDefaultBackground, style.blockButtonDefaultForeground, style.blockButtonPressedBackground, style.blockButtonPressedForeground, text))
  1295.  
  1296. x = x + button.width + space
  1297. end
  1298.  
  1299. y = y + 2
  1300. end
  1301.  
  1302. container:addChild(GUI.adaptiveButton(startX, y, 0, 0, nil, style.blockTextButton, nil, 0x0, localization.sendMessage)).onTouch = function()
  1303. showConversations(friend.id)
  1304. end
  1305.  
  1306. fitToLastChild(container, 1)
  1307. addPanel(container, style.blockBackground)
  1308. end
  1309. end
  1310.  
  1311. addFromList(friends)
  1312.  
  1313. addScrollEventHandler(layout, true, function()
  1314. offset = offset + config.loadCountFriends
  1315.  
  1316. local friends = getFriends()
  1317. if friends then
  1318. addFromList(friends)
  1319. workspace:draw()
  1320. end
  1321. end)
  1322. end
  1323. end
  1324.  
  1325. local newsSelectable = addPizda(localization.news)
  1326. newsSelectable.onTouch = function()
  1327. local function getNews(startFrom)
  1328. return methodRequest("newsfeed.get?filters=post&fields=first_name,last_name,name&count=" .. config.loadCountNews .. (startFrom and ("&start_from=" .. startFrom) or ""))
  1329. end
  1330.  
  1331. local news = getNews(nil)
  1332. if news then
  1333. contentContainer:removeChildren()
  1334.  
  1335. local layout = contentContainer:addChild(GUI.layout(3, 1, contentContainer.width - 4, contentContainer.height, 1, 1))
  1336. layout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  1337. layout:setSpacing(1, 1, 1)
  1338. layout:setMargin(1, 1, 0, 1)
  1339.  
  1340. local function addFromList(list)
  1341. for i = 1, #list.items do
  1342. local item = list.items[i]
  1343.  
  1344. local postContainer = layout:addChild(GUI.container(1, 1, layout.width, 1))
  1345.  
  1346. local post = postContainer:addChild(
  1347. newPost(
  1348. 3,
  1349. 2,
  1350. postContainer.width - 4,
  1351. 6,
  1352. style.blockTitle,
  1353. style.blockText,
  1354. style.blockDate,
  1355. style.blockLine,
  1356. style.blockAttachmentTypeBackground,
  1357. style.blockAttachmentTypeForeground,
  1358. style.blockAttachmentTextBackground,
  1359. style.blockAttachmentTextForeground,
  1360. true,
  1361. list.profiles,
  1362. list.conversations,
  1363. list.groups,
  1364. getSenderName(list.profiles, list.conversations, list.groups, item.source_id),
  1365. "copy_history",
  1366. item
  1367. )
  1368. )
  1369.  
  1370. postContainer.height = post.height + 2
  1371.  
  1372. postContainer:addChild(GUI.panel(1, 1, postContainer.width, postContainer.height, style.blockBackground), 1)
  1373. end
  1374. end
  1375.  
  1376. addFromList(news)
  1377.  
  1378. local nextFrom = news.next_from
  1379. addScrollEventHandler(layout, true, function()
  1380. local newNews = getNews(nextFrom)
  1381. if newNews then
  1382. nextFrom = newNews.next_from
  1383. addFromList(newNews)
  1384. end
  1385. end)
  1386.  
  1387. workspace:draw()
  1388. end
  1389. end
  1390.  
  1391. showConversations = function(peerID)
  1392. local function getConversations(startMessageID)
  1393. return methodRequest("messages.getConversations?filter=all&extended=1&fields=first_name,last_name,online,id&count=" .. config.loadCountConversations .. (startMessageID and "&offset=1" or "") .. (startMessageID and ("&start_message_id=" .. startMessageID) or ""))
  1394. end
  1395.  
  1396. local result = getConversations(nil)
  1397. if result then
  1398. contentContainer:removeChildren()
  1399.  
  1400. local layout = contentContainer:addChild(GUI.layout(1, 1, 28, contentContainer.height, 1, 1))
  1401. layout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  1402. layout:setSpacing(1, 1, 1)
  1403. layout:setMargin(1, 1, 0, 1)
  1404.  
  1405. local conversationPanel = contentContainer:addChild(GUI.panel(layout.width + 1, 1, contentContainer.width - layout.width, contentContainer.height, style.messageSelectedBackground))
  1406. local conversationContainer = contentContainer:addChild(GUI.container(conversationPanel.localX, 1, conversationPanel.width, conversationPanel.height))
  1407.  
  1408. local function conversationDraw(container)
  1409. if container.selected then
  1410. container.senderText.color = style.messageSelectedTitle
  1411. container.messagePreviewText.color = style.messageSelectedText
  1412. container.dateText.color = style.messageSelectedDate
  1413.  
  1414. drawSelection(container, style.messageSelectedBackground, style.blockTitle)
  1415. else
  1416. container.senderText.color = style.messageTitle
  1417. container.messagePreviewText.color = style.messageText
  1418. container.dateText.color = style.messageDate
  1419. end
  1420. -- Спиздим метод у этого контейнера. Надеюсь, он не обидится
  1421. contentContainer.draw(container)
  1422. end
  1423.  
  1424. local function addFromList(list)
  1425. for i = 1, #list.items do
  1426. local item = list.items[i]
  1427.  
  1428. -- Превью текста сообщеньки с вложениями и прочей залупой
  1429. local messagePreview
  1430. if #item.last_message.text == 0 then
  1431. if #item.last_message.fwd_messages > 0 then
  1432. messagePreview = localization.fwdMessages .. #item.last_message.fwd_messages
  1433. elseif #item.last_message.attachments > 0 then
  1434. local data = {}
  1435. for i = 1, #item.last_message.attachments do
  1436. if localization.attachmentsTypes[item.last_message.attachments[i].type] then
  1437. data[i] = localization.attachmentsTypes[item.last_message.attachments[i].type] or "N/A"
  1438. end
  1439. end
  1440.  
  1441. messagePreview = table.concat(data, ", ")
  1442. else
  1443. messagePreview = item.last_message.text
  1444. end
  1445. else
  1446. messagePreview = item.last_message.text
  1447. end
  1448.  
  1449. -- Префиксы для отправленных мною, либо же для имен отправителей в конфах
  1450. if item.last_message.out == 1 then
  1451. messagePreview = localization.you .. messagePreview
  1452. else
  1453. if isPeerChat(item.conversation.peer.id) then
  1454. local eblo = getEblo(list.profiles, item.last_message.from_id)
  1455. messagePreview = eblo.first_name .. ": " .. messagePreview
  1456. end
  1457. end
  1458.  
  1459. local container = addSelectable(layout, "container", 2)
  1460.  
  1461. container.id = item.last_message.id
  1462. container.selected = item.conversation.peer.id == peerID
  1463.  
  1464. local senderName = getSenderName(list.profiles, item.conversation, list.groups, item.conversation.peer.id)
  1465. local avatar = container:addChild(newAvatar(2, 1, 4, 2, getNameShortcut(senderName), item.conversation.peer.id))
  1466.  
  1467. container.senderText = container:addChild(GUI.text(avatar.localX + avatar.width + 1, 1, 0x0, text.limit(senderName, container.width - avatar.width - 9)))
  1468. container.messagePreviewText = container:addChild(GUI.text(container.senderText.localX, 2, 0x0, text.limit(messagePreview, container.width - avatar.width - 3)))
  1469. container.dateText = container:addChild(GUI.text(container.width - 5, 1, 0x0, os.date("%H:%M", item.last_message.date)))
  1470.  
  1471. container.draw = conversationDraw
  1472.  
  1473. container.onTouch = function()
  1474. showHistory(conversationContainer, item.conversation.peer.id)
  1475. end
  1476. end
  1477. end
  1478.  
  1479. addFromList(result)
  1480.  
  1481. addScrollEventHandler(layout, true, function()
  1482. local newConversations = getConversations(layout.children[#layout.children].id)
  1483. if newConversations then
  1484. addFromList(newConversations)
  1485. end
  1486. end)
  1487.  
  1488. if peerID then
  1489. showHistory(conversationContainer, peerID)
  1490. else
  1491. if #layout.children > 0 then
  1492. layout.children[1]:select()
  1493. else
  1494. workspace:draw()
  1495. end
  1496. end
  1497. end
  1498. end
  1499.  
  1500. local conversationsSelectable = addPizda(localization.conversations)
  1501. conversationsSelectable.onTouch = function()
  1502. showConversations()
  1503. end
  1504.  
  1505. local friendsSelectable = addPizda(localization.friends)
  1506. friendsSelectable.onTouch = function()
  1507. showFriends(currentPeerID)
  1508. end
  1509.  
  1510. local function showDocuments()
  1511. local offset = 0
  1512.  
  1513. local function getDocs()
  1514. return methodRequest("docs.get?owner_id=" .. currentPeerID .. "&count=" .. config.loadCountDocs .. "&offset=" .. offset)
  1515. end
  1516.  
  1517. local docs = getDocs()
  1518. if docs then
  1519. contentContainer:removeChildren()
  1520.  
  1521. local layout = contentContainer:addChild(GUI.layout(3, 1, contentContainer.width - 4, contentContainer.height, 1, 1))
  1522. layout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
  1523. layout:setSpacing(1, 1, 1)
  1524. layout:setMargin(1, 1, 0, 1)
  1525.  
  1526. local container = layout:addChild(GUI.container(1, 1, layout.width, 1))
  1527. container:addChild(GUI.keyAndValue(3, 1, style.blockTitle, style.blockText, localization.documentsCount .. ": ", tostring(docs.count)))
  1528.  
  1529. local button = container:addChild(GUI.adaptiveRoundedButton(1, 1, 2, 0, style.blockButtonDefaultBackground, style.blockButtonDefaultForeground, style.blockButtonPressedBackground, style.blockButtonPressedForeground, localization.documentsAdd))
  1530. button.localX = container.width - button.width - 1
  1531. button.onTouch = function()
  1532. local filesystemDialog = GUI.addFilesystemDialog(window, true, 45, window.height - 5, "Open", "Cancel", "File name", "/")
  1533. filesystemDialog:setMode(GUI.IO_MODE_OPEN, GUI.IO_MODE_FILE)
  1534. filesystemDialog.onSubmit = function(path)
  1535. local saveResult = uploadDocument(path)
  1536. if saveResult then
  1537. showDocuments()
  1538. end
  1539. end
  1540. filesystemDialog:show()
  1541. end
  1542.  
  1543. local function addFromList(list)
  1544. for i = 1, #list do
  1545. local item = list[i]
  1546. local container = layout:addChild(GUI.container(1, 1, layout.width, 4))
  1547. addPanel(container, style.blockBackground)
  1548.  
  1549. container:addChild(GUI.text(3, 2, style.blockTitle, item.title))
  1550. container:addChild(GUI.text(3, 3, style.blockText, getAbbreviatedFileSize(item.size, 2) .. ", " .. os.date("%d.%m.%Y %H:%M", item.date)))
  1551. end
  1552. end
  1553.  
  1554. addFromList(docs.items)
  1555.  
  1556. addScrollEventHandler(layout, true, function()
  1557. offset = offset + config.loadCountDocs
  1558. local newDocs = getDocs()
  1559. if newDocs then
  1560. addFromList(newDocs.items)
  1561. end
  1562. end)
  1563. end
  1564.  
  1565. workspace:draw()
  1566. end
  1567.  
  1568. addPizda(localization.documents).onTouch = function()
  1569. showDocuments()
  1570. end
  1571.  
  1572. local function applyStyle()
  1573. window.backgroundPanel.colors.background = style.leftToolbarSelectedBackground
  1574. leftPanel.colors.background = style.leftToolbarDefaultBackground
  1575. progressIndicator.colors.passive, progressIndicator.colors.primary, progressIndicator.colors.secondary = style.UIProgressIndicatorPassive, style.UIProgressIndicatorPrimary, style.UIProgressIndicatorSecondary
  1576.  
  1577. for _, icon in pairs(icons) do
  1578. for y = 1, image.getHeight(icon) do
  1579. for x = 1, image.getWidth(icon) do
  1580. local b, f, a, s = image.get(icon, x, y)
  1581. image.set(icon, x, y, b, style.counterIcon, a, s)
  1582. end
  1583. end
  1584. end
  1585. end
  1586.  
  1587. local settingsSelectable = addPizda(localization.settings)
  1588. settingsSelectable.onTouch = function()
  1589. contentContainer:removeChildren()
  1590.  
  1591. local layout = contentContainer:addChild(GUI.layout(1, 1, contentContainer.width, contentContainer.height, 1, 1))
  1592.  
  1593. local function addYobaSlider(min, max, field)
  1594. local slider = layout:addChild(GUI.slider(1, 1, 36, style.UISliderPrimary, style.UISliderSecondary, style.UISliderPipe, style.UISliderValue, min, max, config[field], false, localization[field] .. ": ", ""))
  1595. slider.roundValues = true
  1596. slider.onValueChanged = function()
  1597. config[field] = number.round(slider.value)
  1598. saveConfig()
  1599. end
  1600. end
  1601.  
  1602. layout:addChild(GUI.text(1, 1, style.UITitle, localization.settingsStyle))
  1603.  
  1604. local comboBox = layout:addChild(GUI.comboBox(1, 1, 36, 3, style.UIComboBoxBackground, style.UIComboBoxForeground, style.UIComboBoxArrowBackground, style.UIComboBoxArrowForeground))
  1605.  
  1606. local list = filesystem.list(stylesPath)
  1607. for i = 1, #list do
  1608. if filesystem.extension(list[i]) == ".lua" then
  1609. comboBox:addItem(filesystem.hideExtension(list[i])).onTouch = function()
  1610. config.style = list[i]
  1611. loadStyle()
  1612. applyStyle()
  1613. lastPizda()
  1614.  
  1615. saveConfig()
  1616. end
  1617.  
  1618. if list[i] == config.style then
  1619. comboBox.selectedItem = comboBox:count()
  1620. end
  1621. end
  1622. end
  1623.  
  1624. layout:addChild(GUI.text(1, 1, style.UITitle, localization.settingsAdditional))
  1625.  
  1626. addYobaSlider(2, 50, "loadCountConversations")
  1627. addYobaSlider(2, 50, "loadCountMessages")
  1628. addYobaSlider(2, 50, "loadCountFriends")
  1629. addYobaSlider(2, 50, "loadCountNews")
  1630. addYobaSlider(2, 50, "loadCountWall")
  1631. addYobaSlider(2, 50, "loadCountDocs")
  1632. addYobaSlider(2, 10, "scrollSpeed")
  1633.  
  1634. workspace:draw()
  1635. end
  1636.  
  1637. local function login()
  1638. local loginContainer = window:addChild(GUI.container(1, 1, window.width, window.height), #window.children)
  1639. addPanel(loginContainer, style.UIBackground)
  1640.  
  1641. local layout = loginContainer:addChild(GUI.layout(1, 1, loginContainer.width, loginContainer.height, 1, 1))
  1642. local logo = layout:addChild(GUI.image(1, 1, image.load(scriptDirectory .. "Icon.pic")))
  1643. logo.height = logo.height + 1
  1644. local usernameInput = layout:addChild(GUI.input(1, 1, 36, 3, style.UIInputBackground, style.UIInputForeground, style.UIInputPlaceholder, style.UIInputBackground, style.UIInputFocusedForeground, config.username or "", localization.username))
  1645. local passwordInput = layout:addChild(GUI.input(1, 1, 36, 3, style.UIInputBackground, style.UIInputForeground, style.UIInputPlaceholder, style.UIInputBackground, style.UIInputFocusedForeground, config.password or "", localization.password, true, "•"))
  1646. local loginButton = layout:addChild(GUI.button(1, 1, 36, 3, style.UIButtonDefaultBackground, style.UIButtonDefaultForeground, style.UIButtonPressedBackground, style.UIButtonPressedForeground, localization.login))
  1647. loginButton.colors.disabled = {
  1648. background = style.UIButtonDisabledBackground,
  1649. text = style.UIButtonDisabledForeground,
  1650. }
  1651. local saveSwitch = layout:addChild(GUI.switchAndLabel(1, 1, 36, 6, style.UISwitchActive, style.UISwitchPassive, style.UISwitchPipe, style.UIText, localization.saveLogin, true))
  1652. local loginusernameInput = layout:addChild(GUI.label(1, 1, 36, 1, style.UIText, localization.invalidPassword))
  1653. loginusernameInput.hidden = true
  1654.  
  1655. usernameInput.onInputFinished = function()
  1656. loginButton.disabled = #usernameInput.text == 0 or #passwordInput.text == 0
  1657. workspace:draw()
  1658. end
  1659. passwordInput.onInputFinished = usernameInput.onInputFinished
  1660.  
  1661. loginButton.onTouch = function()
  1662. local result, reason = request("https://oauth.vk.com/token?grant_type=password&client_id=3697615&client_secret=AlVXZFMUqyrnABp8ncuU&username=" .. internet.encode(usernameInput.text) .. "&password=" .. internet.encode(passwordInput.text) .. "&v=" .. VKAPIVersion)
  1663. if result then
  1664. if result.access_token then
  1665. currentAccessToken = result.access_token
  1666. currentPeerID = result.user_id
  1667. config.accessToken = saveSwitch.switch.state and currentAccessToken or nil
  1668. config.username = saveSwitch.switch.state and usernameInput.text or nil
  1669. config.peerID = saveSwitch.switch.state and currentPeerID or nil
  1670.  
  1671. loginContainer:remove()
  1672. conversationsSelectable:select()
  1673. else
  1674. loginusernameInput.hidden = false
  1675. logout()
  1676. end
  1677.  
  1678. saveConfig()
  1679. end
  1680. end
  1681.  
  1682. lastPizda = login
  1683. usernameInput.onInputFinished()
  1684. workspace:draw()
  1685. end
  1686.  
  1687. local function logout()
  1688. currentAccessToken = nil
  1689. currentPeerID = nil
  1690. config.accessToken = nil
  1691. config.peerID = nil
  1692. login()
  1693. end
  1694.  
  1695. addPizda(localization.exit).onTouch = function()
  1696. logout()
  1697. saveConfig()
  1698. end
  1699.  
  1700. window.onResize = function(width, height)
  1701. leftPanel.width, leftPanel.height = maxPizdaLength + localization.leftBarOffset, height
  1702. leftLayout.width, leftLayout.height = leftPanel.width, leftPanel.height - 2
  1703. progressIndicator.localX, progressIndicator.localY = math.floor(leftPanel.width / 2 - 1), leftPanel.height - progressIndicator.height + 1
  1704.  
  1705. for i = 1, #leftLayout.children do
  1706. leftLayout.children[i].width = leftLayout.width
  1707. end
  1708.  
  1709. window.backgroundPanel.localX, window.backgroundPanel.width, window.backgroundPanel.height = leftPanel.width + 1, width - leftPanel.width, height
  1710. contentContainer.localX, contentContainer.width, contentContainer.height = window.backgroundPanel.localX, window.backgroundPanel.width, window.backgroundPanel.height
  1711. end
  1712.  
  1713. window.onResizeFinished = function()
  1714. if lastPizda then
  1715. lastPizda()
  1716. end
  1717. end
  1718.  
  1719. --------------------------------------------------------------------------------
  1720.  
  1721. currentAccessToken = config.accessToken
  1722. currentPeerID = config.peerID
  1723.  
  1724. window.actionButtons.localX = 3
  1725. window.actionButtons:moveToFront()
  1726. window:resize(window.width, window.height)
  1727. applyStyle()
  1728.  
  1729. if currentAccessToken then
  1730. conversationsSelectable:select()
  1731. else
  1732. login()
  1733. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement