mirror of
https://github.com/IgorTimofeev/MineOS.git
synced 2026-01-10 21:22:39 +01:00
File extension binding feature. File -> open with -> my app <333
This commit is contained in:
parent
7f5db918f4
commit
be7b0add51
@ -4,7 +4,8 @@ local GUI = require("GUI")
|
||||
local screen = require("Screen")
|
||||
local color = require("Color")
|
||||
local system = require("System")
|
||||
local bigLetters = require("bigLetters")
|
||||
local bigLetters = require("BigLetters")
|
||||
local filesystem = require("Filesystem")
|
||||
|
||||
local args, options = system.parseArguments(...)
|
||||
|
||||
|
||||
@ -7,20 +7,11 @@ local system = require("System")
|
||||
local workspace, icon, menu = select(1, ...), select(2, ...), select(3, ...)
|
||||
local localization = system.getSystemLocalization()
|
||||
|
||||
menu:addItem(localization.edit).onTouch = function()
|
||||
system.execute(paths.system.applicationMineCodeIDE, icon.path)
|
||||
end
|
||||
|
||||
menu:addItem(localization.uploadToPastebin, not component.isAvailable("internet")).onTouch = function()
|
||||
system.uploadToPastebin(icon.path)
|
||||
end
|
||||
|
||||
menu:addSeparator()
|
||||
|
||||
menu:addItem(localization.launchWithArguments).onTouch = function()
|
||||
system.launchWithArguments(workspace, icon.path)
|
||||
end
|
||||
|
||||
menu:addItem(localization.flashEEPROM, not component.isAvailable("eeprom") or filesystem.size(icon.path) > 4096).onTouch = function()
|
||||
local container = GUI.addBackgroundContainer(workspace, true, true, localization.flashEEPROM)
|
||||
container.layout:addChild(GUI.label(1, 1, container.width, 1, 0x969696, localization.flashingEEPROM .. "...")):setAlignment(GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP)
|
||||
@ -31,3 +22,7 @@ menu:addItem(localization.flashEEPROM, not component.isAvailable("eeprom") or fi
|
||||
container:remove()
|
||||
workspace:draw()
|
||||
end
|
||||
|
||||
menu:addItem(localization.launchWithArguments).onTouch = function()
|
||||
system.launchWithArguments(workspace, icon.path)
|
||||
end
|
||||
@ -1,14 +0,0 @@
|
||||
|
||||
local paths = require("Paths")
|
||||
local system = require("System")
|
||||
|
||||
local workspace, icon, menu = select(1, ...), select(2, ...), select(3, ...)
|
||||
local localization = system.getSystemLocalization()
|
||||
|
||||
menu:addItem(localization.edit).onTouch = function()
|
||||
system.execute(paths.editor, icon.path)
|
||||
end
|
||||
|
||||
menu:addItem(localization.uploadToPastebin, not component.isAvailable("internet")).onTouch = function()
|
||||
system.uploadToPastebin(icon.path)
|
||||
end
|
||||
@ -1,2 +0,0 @@
|
||||
|
||||
require("System").execute(select(1, ...))
|
||||
@ -1,20 +0,0 @@
|
||||
|
||||
local system = require("System")
|
||||
|
||||
local workspace, icon, menu = select(1, ...), select(2, ...), select(3, ...)
|
||||
local localization = system.getSystemLocalization()
|
||||
local userSettings = system.getUserSettings()
|
||||
|
||||
menu:addItem(localization.setAsWallpaper).onTouch = function()
|
||||
userSettings.interfaceWallpaperEnabled = true
|
||||
userSettings.interfaceWallpaperPath = icon.path
|
||||
|
||||
system.updateWallpaper()
|
||||
workspace:draw()
|
||||
|
||||
system.saveUserSettings()
|
||||
end
|
||||
|
||||
menu:addItem(localization.uploadToPastebin, not component.isAvailable("internet")).onTouch = function()
|
||||
system.uploadToPastebin(icon.path)
|
||||
end
|
||||
@ -1,8 +0,0 @@
|
||||
local path = select(1, ...)
|
||||
|
||||
local success, reason = require("Compressor").unpack(path, require("Filesystem").path(path))
|
||||
if not success then
|
||||
require("GUI").alert(reason)
|
||||
end
|
||||
|
||||
computer.pushSignal("system", "updateFileList")
|
||||
@ -50,28 +50,16 @@
|
||||
{ path="Libraries/Internet.lua" },
|
||||
-- Scripts
|
||||
{ path="OS.lua", id=106 },
|
||||
-- Extensions
|
||||
"Extensions/Lua/Context menu.lua",
|
||||
"Extensions/Lua/Launcher.lua",
|
||||
"Extensions/Pic/Context menu.lua",
|
||||
"Extensions/Pkg/Launcher.lua",
|
||||
"Extensions/3dm/Context menu.lua",
|
||||
-- System icons
|
||||
"Icons/3DModel.pic",
|
||||
"Icons/Application.pic",
|
||||
"Icons/Archive.pic",
|
||||
"Icons/Config.pic",
|
||||
"Icons/FileNotExists.pic",
|
||||
"Icons/Floppy.pic",
|
||||
"Icons/Folder.pic",
|
||||
"Icons/HDD.pic",
|
||||
"Icons/Image.pic",
|
||||
"Icons/Lua.pic",
|
||||
"Icons/Script.pic",
|
||||
"Icons/Text.pic",
|
||||
"Icons/Trash.pic",
|
||||
"Icons/User.pic",
|
||||
"Icons/Localization.pic",
|
||||
-- Sample
|
||||
"Applications/Sample.app/Main.lua",
|
||||
"Applications/Sample.app/Icon.pic",
|
||||
@ -93,6 +81,11 @@
|
||||
"Applications/MineCode IDE.app/Localizations/English.lang",
|
||||
"Applications/MineCode IDE.app/Localizations/French.lang",
|
||||
"Applications/MineCode IDE.app/Localizations/Ukrainian.lang",
|
||||
"Applications/MineCode IDE.app/Extensions/.txt/Icon.pic",
|
||||
"Applications/MineCode IDE.app/Extensions/.cfg/Icon.pic",
|
||||
"Applications/MineCode IDE.app/Extensions/.lang/Icon.pic",
|
||||
"Applications/MineCode IDE.app/Extensions/.lua/Icon.pic",
|
||||
"Applications/MineCode IDE.app/Extensions/.lua/Context menu.lua",
|
||||
-- Picture Edit
|
||||
{ path="Applications/Picture Edit.app/Main.lua", id=798 },
|
||||
"Applications/Picture Edit.app/Icon.pic",
|
||||
@ -104,6 +97,7 @@
|
||||
"Applications/Picture Edit.app/Tools/6.lua",
|
||||
"Applications/Picture Edit.app/Tools/7.lua",
|
||||
"Applications/Picture Edit.app/Tools/8.lua",
|
||||
"Applications/Picture Edit.app/Extensions/.pic/Icon.pic",
|
||||
-- Finder
|
||||
{ path="Applications/Finder.app/Main.lua", id=175 },
|
||||
"Applications/Finder.app/Icon.pic",
|
||||
@ -153,6 +147,7 @@
|
||||
"Applications/3D Print.app/Localizations/Russian.lang",
|
||||
"Applications/3D Print.app/Localizations/French.lang",
|
||||
"Applications/3D Print.app/Localizations/Ukrainian.lang",
|
||||
"Applications/3D Print.app/Extensions/.3dm/Icon.pic",
|
||||
-- Weather
|
||||
{ path="Applications/Weather.app/Main.lua", id=240, shortcut = true },
|
||||
"Applications/Weather.app/Icon.pic",
|
||||
|
||||
@ -116,39 +116,12 @@ function system.getDefaultUserSettings()
|
||||
filesystem.path(paths.system.applicationSettings),
|
||||
},
|
||||
extensions = {
|
||||
[".3dm"] = {
|
||||
icon = paths.system.icons .. "3DModel.pic",
|
||||
launcher = paths.system.applications .. "3D Print.app/Main.lua",
|
||||
contextMenu = paths.system.extensions .. "3dm/Context menu.lua"
|
||||
},
|
||||
[".pic"] = {
|
||||
icon = paths.system.icons .. "Image.pic",
|
||||
launcher = paths.system.applicationPictureEdit,
|
||||
contextMenu = paths.system.extensions .. "Pic/Context menu.lua"
|
||||
},
|
||||
[".cfg"] = {
|
||||
icon = paths.system.icons .. "Config.pic"
|
||||
},
|
||||
[".txt"] = {
|
||||
icon = paths.system.icons .. "Text.pic"
|
||||
},
|
||||
[".lang"] = {
|
||||
icon = paths.system.icons .. "Localization.pic"
|
||||
},
|
||||
[".pkg"] = {
|
||||
icon = paths.system.icons .. "Archive.pic",
|
||||
launcher = paths.system.extensions .. "Pkg/Launcher.lua",
|
||||
},
|
||||
[".lua"] = {
|
||||
icon = paths.system.icons .. "Lua.pic",
|
||||
launcher = paths.system.extensions .. "Lua/Launcher.lua",
|
||||
contextMenu = paths.system.extensions .. "Lua/Context menu.lua"
|
||||
},
|
||||
["script"] = {
|
||||
icon = paths.system.icons .. "Script.pic",
|
||||
launcher = paths.system.extensions .. "Lua/Launcher.lua",
|
||||
contextMenu = paths.system.extensions .. "Lua/Context menu.lua"
|
||||
},
|
||||
[".lua"] = filesystem.path(paths.system.applicationMineCodeIDE),
|
||||
[".cfg"] = filesystem.path(paths.system.applicationMineCodeIDE),
|
||||
[".txt"] = filesystem.path(paths.system.applicationMineCodeIDE),
|
||||
[".lang"] = filesystem.path(paths.system.applicationMineCodeIDE),
|
||||
[".pic"] = filesystem.path(paths.system.applicationPictureEdit),
|
||||
[".3dm"] = paths.system.applications .. "3D Print.app/"
|
||||
},
|
||||
}
|
||||
end
|
||||
@ -345,14 +318,14 @@ local iconLaunchers = {
|
||||
|
||||
extension = function(icon)
|
||||
if icon.isShortcut then
|
||||
system.execute(userSettings.extensions[icon.shortcutExtension].launcher, icon.shortcutPath, "-o")
|
||||
system.execute(userSettings.extensions[icon.shortcutExtension] .. "Main.lua", icon.shortcutPath, "-o")
|
||||
else
|
||||
system.execute(userSettings.extensions[icon.extension].launcher, icon.path, "-o")
|
||||
system.execute(userSettings.extensions[icon.extension] .. "Main.lua", icon.path, "-o")
|
||||
end
|
||||
end,
|
||||
|
||||
script = function(icon)
|
||||
system.execute(icon.path)
|
||||
system.execute(paths.system.applicationMineCodeIDE, icon.path)
|
||||
end,
|
||||
|
||||
showPackageContent = function(icon)
|
||||
@ -368,6 +341,15 @@ local iconLaunchers = {
|
||||
|
||||
workspace:draw()
|
||||
end,
|
||||
|
||||
archive = function(icon)
|
||||
local success, reason = require("Compressor").unpack(icon.path, filesystem.path(icon.path))
|
||||
if success then
|
||||
computer.pushSignal("system", "updateFileList")
|
||||
else
|
||||
GUI.alert(reason)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
function system.calculateIconProperties()
|
||||
@ -515,23 +497,7 @@ local function iconAnalyseExtension(icon, launchers)
|
||||
if icon.isDirectory then
|
||||
if icon.extension == ".app" then
|
||||
if userSettings.filesShowApplicationIcon then
|
||||
if filesystem.exists(icon.path .. "Icon.pic") then
|
||||
icon.image = image.load(icon.path .. "Icon.pic")
|
||||
elseif filesystem.exists(icon.path .. "Icon.lua") then
|
||||
local result, reason = loadfile(icon.path .. "Icon.lua")
|
||||
if result then
|
||||
result, reason = pcall(result)
|
||||
if result then
|
||||
icon.liveImage = reason
|
||||
else
|
||||
error("Failed to load live icon image: " .. tostring(reason))
|
||||
end
|
||||
else
|
||||
error("Failed to load live icon image: " .. tostring(reason))
|
||||
end
|
||||
else
|
||||
icon.image = iconCache.fileNotExists
|
||||
end
|
||||
icon.image = image.load(icon.path .. "Icon.pic") or iconCache.fileNotExists
|
||||
else
|
||||
icon.image = iconCache.application
|
||||
end
|
||||
@ -563,17 +529,22 @@ local function iconAnalyseExtension(icon, launchers)
|
||||
icon.image = shortcutIcon.image
|
||||
icon.shortcutLaunch = shortcutIcon.launch
|
||||
icon.launch = launchers.shortcut
|
||||
elseif icon.extension == ".pkg" then
|
||||
icon.image = iconCache.archive
|
||||
icon.launch = launchers.archive
|
||||
elseif userSettings.extensions[icon.extension] then
|
||||
icon.image =
|
||||
image.load(userSettings.extensions[icon.extension] .. "Extensions/" .. icon.extension .. "/Icon.pic") or
|
||||
image.load(userSettings.extensions[icon.extension] .. "Icon.pic") or
|
||||
iconCache.fileNotExists
|
||||
|
||||
icon.launch = launchers.extension
|
||||
elseif not filesystem.exists(icon.path) then
|
||||
icon.image = iconCache.fileNotExists
|
||||
icon.launch = launchers.corrupted
|
||||
else
|
||||
if userSettings.extensions[icon.extension] then
|
||||
icon.launch = launchers.extension
|
||||
icon.image = system.cacheIcon(icon.extension, userSettings.extensions[icon.extension].icon)
|
||||
else
|
||||
icon.launch = launchers.script
|
||||
icon.image = iconCache.script
|
||||
end
|
||||
icon.image = iconCache.script
|
||||
icon.launch = launchers.script
|
||||
end
|
||||
end
|
||||
|
||||
@ -765,6 +736,10 @@ local function iconOnRightClick(icon, e1, e2, e3, e4)
|
||||
if #selectedIcons == 1 then
|
||||
if icon.isDirectory then
|
||||
if icon.extension == ".app" then
|
||||
contextMenu:addItem(localization.edit .. " Main.lua").onTouch = function()
|
||||
system.execute(paths.system.applicationMineCodeIDE, icon.path .. "Main.lua")
|
||||
end
|
||||
|
||||
contextMenu:addItem(localization.showPackageContent).onTouch = function()
|
||||
icon.parent.parent.launchers.showPackageContent(icon)
|
||||
end
|
||||
@ -790,10 +765,6 @@ local function iconOnRightClick(icon, e1, e2, e3, e4)
|
||||
workspace:draw()
|
||||
end
|
||||
|
||||
contextMenu:addItem(localization.edit .. " Main.lua").onTouch = function()
|
||||
system.execute(paths.system.applicationMineCodeIDE, icon.path .. "Main.lua")
|
||||
end
|
||||
|
||||
contextMenu:addSeparator()
|
||||
end
|
||||
|
||||
@ -842,33 +813,70 @@ local function iconOnRightClick(icon, e1, e2, e3, e4)
|
||||
end
|
||||
|
||||
contextMenu:addSeparator()
|
||||
else
|
||||
if userSettings.extensions[icon.extension] and userSettings.extensions[icon.extension].contextMenu then
|
||||
local success, reason = pcall(loadfile(userSettings.extensions[icon.extension].contextMenu), workspace, icon, contextMenu)
|
||||
if success then
|
||||
contextMenu:addSeparator()
|
||||
else
|
||||
GUI.alert("Failed to load extension association: " .. tostring(reason))
|
||||
end
|
||||
else
|
||||
contextMenu:addItem(localization.edit).onTouch = function()
|
||||
system.execute(paths.system.applicationMineCodeIDE, icon.path)
|
||||
end
|
||||
|
||||
else
|
||||
local function addDefault()
|
||||
contextMenu:addItem(localization.uploadToPastebin, not component.isAvailable("internet")).onTouch = function()
|
||||
system.uploadToPastebin(icon.path)
|
||||
end
|
||||
|
||||
contextMenu:addSeparator()
|
||||
end
|
||||
|
||||
-- local subMenu = contextMenu:addSubMenuItem(localization.openWith)
|
||||
-- local fileList = filesystem.sortedList(paths.system.applications, "name")
|
||||
-- subMenu:addItem(localization.select)
|
||||
-- subMenu:addSeparator()
|
||||
-- for i = 1, #fileList do
|
||||
-- subMenu:addItem(fileList[i].nameWithoutExtension)
|
||||
-- end
|
||||
if userSettings.extensions[icon.extension] then
|
||||
local result, reason = loadfile(userSettings.extensions[icon.extension] .. "Extensions/" .. icon.extension .. "/Context menu.lua")
|
||||
if result then
|
||||
result, reason = pcall(result, workspace, icon, contextMenu)
|
||||
|
||||
if result then
|
||||
contextMenu:addSeparator()
|
||||
else
|
||||
GUI.alert("Failed to load extension association: " .. tostring(reason))
|
||||
end
|
||||
else
|
||||
addDefault()
|
||||
end
|
||||
else
|
||||
addDefault()
|
||||
end
|
||||
|
||||
-- Open with
|
||||
local subMenu = contextMenu:addSubMenuItem(localization.openWith)
|
||||
|
||||
local function setAssociation(path)
|
||||
userSettings.extensions[icon.extension] = path
|
||||
|
||||
icon:analyseExtension(icon.parent.parent.launchers)
|
||||
icon:launch()
|
||||
workspace:draw()
|
||||
|
||||
system.saveUserSettings()
|
||||
end
|
||||
|
||||
subMenu:addItem(localization.select).onTouch = function()
|
||||
local filesystemDialog = GUI.addFilesystemDialog(workspace, true, 50, math.floor(workspace.height * 0.8), localization.open, localization.cancel, localization.fileName, "/")
|
||||
|
||||
filesystemDialog:setMode(GUI.IO_MODE_OPEN, GUI.IO_MODE_DIRECTORY)
|
||||
filesystemDialog:addExtensionFilter(".app")
|
||||
filesystemDialog:expandPath(paths.system.applications)
|
||||
filesystemDialog.filesystemTree.selectedItem = userSettings.extensions[icon.extension]
|
||||
filesystemDialog.onSubmit = function(path)
|
||||
setAssociation(path)
|
||||
end
|
||||
|
||||
filesystemDialog:show()
|
||||
end
|
||||
|
||||
subMenu:addSeparator()
|
||||
|
||||
local list = filesystem.list(paths.system.applications)
|
||||
for i = 1, #list do
|
||||
local path = paths.system.applications .. list[i]
|
||||
|
||||
if filesystem.isDirectory(path) and filesystem.extension(list[i]) == ".app" then
|
||||
subMenu:addItem(filesystem.hideExtension(list[i])).onTouch = function()
|
||||
setAssociation(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -897,50 +905,6 @@ local function iconOnRightClick(icon, e1, e2, e3, e4)
|
||||
contextMenu:addSeparator()
|
||||
end
|
||||
|
||||
local subMenu = contextMenu:addSubMenuItem(localization.archive .. (#selectedIcons > 1 and " (" .. #selectedIcons .. ")" or ""))
|
||||
|
||||
local function archive(where)
|
||||
local itemsToArchive = {}
|
||||
for i = 1, #selectedIcons do
|
||||
table.insert(itemsToArchive, selectedIcons[i].path)
|
||||
end
|
||||
|
||||
local success, reason = require("Compressor").pack(where .. "/Archive.pkg", itemsToArchive)
|
||||
if not success then
|
||||
GUI.alert(reason)
|
||||
end
|
||||
|
||||
computer.pushSignal("system", "updateFileList")
|
||||
end
|
||||
|
||||
subMenu:addItem(localization.inCurrentDirectory).onTouch = function()
|
||||
archive(filesystem.path(icon.path))
|
||||
end
|
||||
|
||||
subMenu:addItem(localization.onDesktop).onTouch = function()
|
||||
archive(paths.user.desktop)
|
||||
end
|
||||
|
||||
local function cutOrCopy(cut)
|
||||
for i = 1, #icon.parent.children do
|
||||
icon.parent.children[i].cut = nil
|
||||
end
|
||||
|
||||
system.clipboard = {cut = cut}
|
||||
for i = 1, #selectedIcons do
|
||||
selectedIcons[i].cut = cut
|
||||
table.insert(system.clipboard, selectedIcons[i].path)
|
||||
end
|
||||
end
|
||||
|
||||
contextMenu:addItem(localization.cut).onTouch = function()
|
||||
cutOrCopy(true)
|
||||
end
|
||||
|
||||
contextMenu:addItem(localization.copy).onTouch = function()
|
||||
cutOrCopy()
|
||||
end
|
||||
|
||||
if not icon.isShortcut or #selectedIcons > 1 then
|
||||
local subMenu = contextMenu:addSubMenuItem(localization.createShortcut)
|
||||
|
||||
@ -971,6 +935,59 @@ local function iconOnRightClick(icon, e1, e2, e3, e4)
|
||||
end
|
||||
end
|
||||
|
||||
local subMenu = contextMenu:addSubMenuItem(localization.archive .. (#selectedIcons > 1 and " (" .. #selectedIcons .. ")" or ""))
|
||||
|
||||
local function archive(where)
|
||||
local itemsToArchive = {}
|
||||
for i = 1, #selectedIcons do
|
||||
table.insert(itemsToArchive, selectedIcons[i].path)
|
||||
end
|
||||
|
||||
local success, reason = require("Compressor").pack(where .. "/Archive.pkg", itemsToArchive)
|
||||
if not success then
|
||||
GUI.alert(reason)
|
||||
end
|
||||
|
||||
computer.pushSignal("system", "updateFileList")
|
||||
end
|
||||
|
||||
subMenu:addItem(localization.inCurrentDirectory).onTouch = function()
|
||||
archive(filesystem.path(icon.path))
|
||||
end
|
||||
|
||||
subMenu:addItem(localization.onDesktop).onTouch = function()
|
||||
archive(paths.user.desktop)
|
||||
end
|
||||
|
||||
if #selectedIcons == 1 then
|
||||
contextMenu:addItem(localization.addToDock).onTouch = function()
|
||||
dockContainer.addIcon(icon.path).keepInDock = true
|
||||
dockContainer.saveUserSettings()
|
||||
end
|
||||
end
|
||||
|
||||
contextMenu:addSeparator()
|
||||
|
||||
local function cutOrCopy(cut)
|
||||
for i = 1, #icon.parent.children do
|
||||
icon.parent.children[i].cut = nil
|
||||
end
|
||||
|
||||
system.clipboard = {cut = cut}
|
||||
for i = 1, #selectedIcons do
|
||||
selectedIcons[i].cut = cut
|
||||
table.insert(system.clipboard, selectedIcons[i].path)
|
||||
end
|
||||
end
|
||||
|
||||
contextMenu:addItem(localization.cut).onTouch = function()
|
||||
cutOrCopy(true)
|
||||
end
|
||||
|
||||
contextMenu:addItem(localization.copy).onTouch = function()
|
||||
cutOrCopy()
|
||||
end
|
||||
|
||||
if #selectedIcons == 1 then
|
||||
contextMenu:addItem(localization.rename).onTouch = function()
|
||||
local container = addBackgroundContainerWithInput(filesystem.name(icon.path), localization.rename, localization.newName)
|
||||
@ -1006,13 +1023,6 @@ local function iconOnRightClick(icon, e1, e2, e3, e4)
|
||||
|
||||
contextMenu:addSeparator()
|
||||
|
||||
if #selectedIcons == 1 then
|
||||
contextMenu:addItem(localization.addToDock).onTouch = function()
|
||||
dockContainer.addIcon(icon.path).keepInDock = true
|
||||
dockContainer.saveUserSettings()
|
||||
end
|
||||
end
|
||||
|
||||
contextMenu:addItem(localization.properties).onTouch = function()
|
||||
for i = 1, #selectedIcons do
|
||||
system.addPropertiesWindow(e3, e4, 46, selectedIcons[i])
|
||||
@ -2659,6 +2669,7 @@ bootRealTime = math.floor(filesystem.lastModified(temporaryPath) / 1000)
|
||||
filesystem.remove(temporaryPath)
|
||||
|
||||
-- Caching commonly used icons
|
||||
system.cacheIcon("archive", paths.system.icons .. "Archive.pic")
|
||||
system.cacheIcon("directory", paths.system.icons .. "Folder.pic")
|
||||
system.cacheIcon("fileNotExists", paths.system.icons .. "FileNotExists.pic")
|
||||
system.cacheIcon("application", paths.system.icons .. "Application.pic")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user