Defxult / discordLevelingSystem

A library to implement a leveling system into a discord bot. Contains features such as XP, level, ranks, and role awards.
MIT License
91 stars 17 forks source link

feat: add rank card #17

Closed krishsharma0413 closed 2 years ago

krishsharma0413 commented 2 years ago

@Defxult please review code.

errors

rank_card.py

todo

krishsharma0413 commented 2 years ago

also send me a friend request on discord resetxd#8278 since it's a little slow on github :v

Defxult commented 2 years ago

How are you sending the card in discord?

krishsharma0413 commented 2 years ago

example: disnake.File(fp=return_from_method, filename="rank.png") should work

If path is provided then its easier to use the path provided in the File class of any discord.py library (with this the image will be stored somewhere) If no provided it returns Bytes that can be used in the File class again. (with this the file will not be stored anywhere and will be removed from the memory once used)

Defxult commented 2 years ago

Well, the library uses discord.py 2.0..but I don't think that changed drastically

But I'm using

@bot.command()
async def test(ctx: commands.Context):
    data = await lvl.get_data_for(ctx.author)
    kim = open('./background.png', mode='rb')
    av = open('./avt.png', mode='rb')
    card = RankCard(
        background=kim,
        avatar=av,
        level=data.level,
        username=data.name,
        current_exp=data.xp,
        max_exp=await lvl.next_level_up(ctx.author)
    )
    rc = await card.card()
    await ctx.send(file=discord.File(rc, filename='rank.png'))

Which results in

    await ctx.send(file=discord.File(rc, filename='rank.png'))
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/discord/file.py", line 97, in __init__
    self.fp = open(fp, 'rb')
ValueError: embedded null byte

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/discord/ext/commands/bot.py", line 1347, in invoke
    await ctx.command.invoke(ctx)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/discord/ext/commands/core.py", line 986, in invoke
    await injected(*ctx.args, **ctx.kwargs)  # type: ignore
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/discord/ext/commands/core.py", line 199, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: ValueError: embedded null byte
krishsharma0413 commented 2 years ago

hmmm, i have to check discord.py then because when i tested on disnake, nextcord it worked without any issue.

krishsharma0413 commented 2 years ago

~~@Defxult the code you provided seems to work for me though, are you sure that the images and data provided is correct? maybe add a print statement too just to be sure of it~~

code i used to check with

@bot.command()
async def test(ctx: commands.Context):
    a = RankCard(
        background="./test.png",
        avatar=open("./test.png", "rb"),
        level=1,
        current_exp=1,
        max_exp=1,
        username="test",
        path="./test.png"
    )
    rc = await a.card()
    await ctx.send(file=discord.File(rc, filename='rank.png'))

PS: wait let me check again i am using path rn

krishsharma0413 commented 2 years ago

It should work now @Defxult

Defxult commented 2 years ago

There we go, that works 👍. Is this ready for review btw? There's some things that need I would like changed but I see you're still adding stuff. If not just mark it ready so I can take a deeper look at it as well

krishsharma0413 commented 2 years ago

alright

krishsharma0413 commented 2 years ago

@Defxult i updated almost all of the code and made something like this,

instead of adding background, text_color, bar_color again and again, i made a class Settings that keeps that and you can pass that as an argument.

get_rank_card is a thing now but i haven't tested it yet since i don't have a proper database.

setup.py install_requires is fixed but i am not sure about if /assets folder is included or not

docstring to almost all classes and methods is done.

did i left something out?

krishsharma0413 commented 2 years ago

also can you please be a little bit more active in discord and send me a friend request since github is being too slow and productivity is decreasing by a lot. resetxd#8278

krishsharma0413 commented 2 years ago

ahh

Defxult commented 2 years ago

So I've been testing the rank card and:

⚠️ In the _convert_number method, the billion number if statement should be removed because this library only goes up to millions for XP. Also, the millions return, set it to .3f instead of .1f. With such a large number, having only 1 decimal place makes the rank card appear very inaccurate when reaching high levels, and setting it to .3f corrects that.


⚠️ In the create method, the doc string states it raises InvalidImageType and InvalidImageUrl, but TypeError is raised instead of InvalidImageUrl

⚠️ In method get_rank_card, the doc string states it returns BytesIO. Should be Optional[BytesIO].

⚠️ In the Settings class __init__ , remove the Optional from the parameter

⚠️ In the Settings class doc string, it states it can accept a hex code. Hex codes are int, but the parameter is type hinted for str. Should be Union[int, str]? Also, using a hex code with bar_color makes the progress bar disappear. Using a hex code with text_color does not set it to the expected color. It's changed to a very faded/dark/random color. Only using strings such as "blue" or "red" for bar_color and text_color works as intended.

Defxult commented 2 years ago

Nice. I only need you to add 1 more thing. Then I'll have to make a few changes on my end then merge. But as of right now, the colors for the bar and text should be in a separate class. Meaning, I want the library to be more user friendly when it comes to the end user picking a color. Instead of having the end user type out each color for bar_color and text_color, there needs to be a class that contains ALL available colors the user can pick from. Example:

class _Color:
    white: ClassVar[str] = 'white'
    blue: ClassVar[str] = 'blue'
    # ... listing all available colors

class Settings:
    Color = _Color

So when picking a color, it'll look something like

settings = Settings(
    background='...',
    bar_color=Settings.Color.white,
    text_color=Settings.Color.blue
)
krishsharma0413 commented 2 years ago

alright then let me work on the class then