Skip to content

Commit e5d0110

Browse files
committed
first pass on container component api
1 parent 22c363f commit e5d0110

File tree

5 files changed

+396
-0
lines changed

5 files changed

+396
-0
lines changed
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package io.github.kaktushose.jdac.components.container;
2+
3+
import io.github.kaktushose.jdac.introspection.Introspection;
4+
import io.github.kaktushose.jdac.message.placeholder.Entry;
5+
import io.github.kaktushose.jdac.message.resolver.ComponentResolver;
6+
import io.github.kaktushose.jdac.message.resolver.Resolver;
7+
import net.dv8tion.jda.api.components.MessageTopLevelComponentUnion;
8+
import net.dv8tion.jda.api.components.actionrow.ActionRow;
9+
import net.dv8tion.jda.api.components.container.Container;
10+
import net.dv8tion.jda.api.components.container.ContainerChildComponent;
11+
import net.dv8tion.jda.api.components.container.ContainerChildComponentUnion;
12+
import net.dv8tion.jda.api.components.filedisplay.FileDisplay;
13+
import net.dv8tion.jda.api.components.mediagallery.MediaGallery;
14+
import net.dv8tion.jda.api.components.replacer.ComponentReplacer;
15+
import net.dv8tion.jda.api.components.section.Section;
16+
import net.dv8tion.jda.api.components.separator.Separator;
17+
import net.dv8tion.jda.api.components.textdisplay.TextDisplay;
18+
import net.dv8tion.jda.api.interactions.DiscordLocale;
19+
import net.dv8tion.jda.api.utils.data.DataObject;
20+
import net.dv8tion.jda.internal.components.AbstractComponentImpl;
21+
import net.dv8tion.jda.internal.components.container.ContainerImpl;
22+
import org.jetbrains.annotations.Unmodifiable;
23+
import org.jspecify.annotations.Nullable;
24+
25+
import java.util.*;
26+
import java.util.stream.Stream;
27+
28+
public sealed class BaseContainer<T extends ContainerChildComponent>
29+
extends AbstractComponentImpl
30+
implements Container, MessageTopLevelComponentUnion
31+
permits SeparatorContainer {
32+
33+
protected final List<Entry> entries;
34+
private final ComponentResolver<Container> resolver;
35+
protected int uniqueId;
36+
protected Container container;
37+
private Locale locale;
38+
39+
public BaseContainer(Resolver<String> resolver, DiscordLocale locale, T header) {
40+
this(resolver, locale.toLocale(), header);
41+
}
42+
43+
public BaseContainer(Resolver<String> resolver, Locale locale, T header) {
44+
this.resolver = new ComponentResolver<>(resolver, Container.class);
45+
this.locale = locale;
46+
entries = new ArrayList<>();
47+
uniqueId = -1;
48+
container = Container.of(header);
49+
}
50+
51+
protected static void checkAccess() {
52+
if (!Introspection.accessible()) {
53+
throw new IllegalStateException("TODO: Illegal call outside of of event handler");
54+
}
55+
}
56+
57+
public BaseContainer<T> add(T component) {
58+
var components = new ArrayList<>(container.getComponents());
59+
components.add((ContainerChildComponentUnion) component);
60+
container = Container.of(components);
61+
return this;
62+
}
63+
64+
public BaseContainer<T> addFirst(T component) {
65+
var components = new ArrayList<>(container.getComponents());
66+
components.addFirst((ContainerChildComponentUnion) component);
67+
container = Container.of(components);
68+
return this;
69+
}
70+
71+
public BaseContainer<T> addLast(T component) {
72+
var components = new ArrayList<>(container.getComponents());
73+
components.addLast((ContainerChildComponentUnion) component);
74+
container = Container.of(components);
75+
return this;
76+
}
77+
78+
public Locale locale() {
79+
return locale;
80+
}
81+
82+
public BaseContainer<T> locale(Locale locale) {
83+
this.locale = locale;
84+
return this;
85+
}
86+
87+
public BaseContainer<T> locale(DiscordLocale locale) {
88+
this.locale = locale.toLocale();
89+
return this;
90+
}
91+
92+
@Override
93+
public @Unmodifiable List<ContainerChildComponentUnion> getComponents() {
94+
if (!Introspection.accessible()) {
95+
container = resolver.resolve(container, locale, toMap());
96+
}
97+
return container.getComponents();
98+
}
99+
100+
@Override
101+
public DataObject toData() {
102+
if (!Introspection.accessible()) {
103+
container = resolver.resolve(container, locale, toMap());
104+
}
105+
return ((ContainerImpl) container).toData();
106+
}
107+
108+
@Override
109+
public Type getType() {
110+
return Type.CONTAINER;
111+
}
112+
113+
@Override
114+
public int getUniqueId() {
115+
return uniqueId;
116+
}
117+
118+
@Override
119+
public BaseContainer<T> withUniqueId(int uniqueId) {
120+
this.uniqueId = uniqueId;
121+
return this;
122+
}
123+
124+
@Override
125+
public BaseContainer<T> replace(ComponentReplacer replacer) {
126+
container = container.replace(replacer);
127+
return this;
128+
}
129+
130+
@Override
131+
public ActionRow asActionRow() {
132+
throw new UnsupportedOperationException();
133+
}
134+
135+
@Override
136+
public Section asSection() {
137+
throw new UnsupportedOperationException();
138+
}
139+
140+
@Override
141+
public TextDisplay asTextDisplay() {
142+
throw new UnsupportedOperationException();
143+
}
144+
145+
@Override
146+
public MediaGallery asMediaGallery() {
147+
throw new UnsupportedOperationException();
148+
}
149+
150+
@Override
151+
public Separator asSeparator() {
152+
throw new UnsupportedOperationException();
153+
}
154+
155+
@Override
156+
public FileDisplay asFileDisplay() {
157+
throw new UnsupportedOperationException();
158+
}
159+
160+
@Override
161+
public Container asContainer() {
162+
return container;
163+
}
164+
165+
@Override
166+
public BaseContainer<T> withAccentColor(@Nullable Integer accentColor) {
167+
container = container.withAccentColor(accentColor);
168+
return this;
169+
}
170+
171+
@Override
172+
public BaseContainer<T> withSpoiler(boolean spoiler) {
173+
container = container.withSpoiler(spoiler);
174+
return this;
175+
}
176+
177+
@Override
178+
public BaseContainer<T> withComponents(ContainerChildComponent component, ContainerChildComponent... components) {
179+
return withComponents(Stream.concat(Stream.of(component), Arrays.stream(components)).toList());
180+
}
181+
182+
@Override
183+
public BaseContainer<T> withComponents(Collection<? extends ContainerChildComponent> components) {
184+
container = container.withComponents(components);
185+
return this;
186+
}
187+
188+
@Override
189+
public @Nullable Integer getAccentColorRaw() {
190+
return container.getAccentColorRaw();
191+
}
192+
193+
@Override
194+
public boolean isSpoiler() {
195+
return container.isSpoiler();
196+
}
197+
198+
private Map<String, @Nullable Object> toMap() {
199+
return Entry.toMap(entries.toArray(Entry[]::new));
200+
}
201+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package io.github.kaktushose.jdac.components.container;
2+
3+
import io.github.kaktushose.jdac.configuration.Property;
4+
import io.github.kaktushose.jdac.introspection.Introspection;
5+
import io.github.kaktushose.jdac.message.resolver.Resolver;
6+
import net.dv8tion.jda.api.components.container.ContainerChildComponent;
7+
import net.dv8tion.jda.api.components.separator.Separator;
8+
import net.dv8tion.jda.api.interactions.DiscordLocale;
9+
import org.jspecify.annotations.Nullable;
10+
11+
import java.util.Locale;
12+
import java.util.function.Consumer;
13+
14+
/// special handling of [TextDisplayContainer]
15+
public final class SeparatorContainer extends BaseContainer<ContainerChildComponent> {
16+
17+
private final Separator separator;
18+
19+
public SeparatorContainer(Resolver<String> resolver, DiscordLocale locale, ContainerChildComponent header, Separator separator) {
20+
this(resolver, locale.toLocale(), header, separator);
21+
}
22+
23+
public SeparatorContainer(Resolver<String> resolver, Locale locale, ContainerChildComponent header, Separator separator) {
24+
super(resolver, locale, header);
25+
super.add(separator);
26+
this.separator = separator;
27+
}
28+
29+
public static SeparatorContainer of(ContainerChildComponent header, Separator separator) {
30+
BaseContainer.checkAccess();
31+
return new SeparatorContainer(
32+
Introspection.scopedGet(Property.MESSAGE_RESOLVER),
33+
Introspection.scopedGet(Property.JDA_EVENT).getUserLocale().toLocale(),
34+
header,
35+
separator
36+
);
37+
}
38+
39+
@Override
40+
public SeparatorContainer add(ContainerChildComponent component) {
41+
add(component, super::add);
42+
super.add(separator);
43+
return this;
44+
}
45+
46+
public SeparatorContainer add(ContainerChildComponent component, @Nullable Separator separator) {
47+
add(component, super::add);
48+
if (separator != null) {
49+
super.add(separator);
50+
}
51+
return this;
52+
}
53+
54+
@Override
55+
public SeparatorContainer addFirst(ContainerChildComponent component) {
56+
super.addFirst(separator);
57+
add(component, super::addFirst);
58+
return this;
59+
}
60+
61+
/// doesn't add separator
62+
@Override
63+
public SeparatorContainer addLast(ContainerChildComponent component) {
64+
add(component, super::addLast);
65+
return this;
66+
}
67+
68+
private void add(ContainerChildComponent component, Consumer<ContainerChildComponent> consumer) {
69+
if (component instanceof TextDisplayContainer textDisplay) {
70+
textDisplay.textDisplays().stream().map(ContainerChildComponent.class::cast).forEach(consumer);
71+
} else {
72+
consumer.accept(component);
73+
}
74+
}
75+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package io.github.kaktushose.jdac.components.container;
2+
3+
import io.github.kaktushose.jdac.configuration.Property;
4+
import io.github.kaktushose.jdac.introspection.Introspection;
5+
import io.github.kaktushose.jdac.message.resolver.Resolver;
6+
import net.dv8tion.jda.api.components.textdisplay.TextDisplay;
7+
import net.dv8tion.jda.api.components.utils.ComponentSerializer;
8+
import net.dv8tion.jda.api.interactions.DiscordLocale;
9+
import net.dv8tion.jda.api.utils.data.DataObject;
10+
import net.dv8tion.jda.internal.components.textdisplay.TextDisplayImpl;
11+
12+
import java.util.Collection;
13+
import java.util.Locale;
14+
import java.util.stream.Collectors;
15+
16+
public final class TextDisplayContainer extends TextDisplayImpl {
17+
18+
private static final ComponentSerializer componentSerializer = new ComponentSerializer();
19+
private BaseContainer<TextDisplay> container;
20+
21+
public TextDisplayContainer(Resolver<String> resolver, DiscordLocale locale, String header) {
22+
this(resolver, locale.toLocale(), header);
23+
}
24+
25+
public TextDisplayContainer(Resolver<String> resolver, DiscordLocale locale, TextDisplay header) {
26+
this(resolver, locale.toLocale(), header);
27+
}
28+
29+
public TextDisplayContainer(Resolver<String> resolver, Locale locale, String header) {
30+
this(resolver, locale, TextDisplay.of(header));
31+
}
32+
33+
public TextDisplayContainer(Resolver<String> resolver, Locale locale, TextDisplay header) {
34+
super(componentSerializer.serialize(header));
35+
container = new BaseContainer<>(resolver, locale, header);
36+
}
37+
38+
public static TextDisplayContainer of(String content) {
39+
return of(TextDisplay.of(content));
40+
}
41+
42+
public static TextDisplayContainer of(TextDisplay header) {
43+
BaseContainer.checkAccess();
44+
return new TextDisplayContainer(
45+
Introspection.scopedGet(Property.MESSAGE_RESOLVER),
46+
Introspection.scopedGet(Property.JDA_EVENT).getUserLocale().toLocale(),
47+
header
48+
);
49+
}
50+
51+
public TextDisplayContainer add(String content) {
52+
container.add(TextDisplay.of(content));
53+
return this;
54+
}
55+
56+
public TextDisplayContainer addFirst(String content) {
57+
container.addFirst(TextDisplay.of(content));
58+
return this;
59+
}
60+
61+
public TextDisplayContainer addLast(String content) {
62+
container.addLast(TextDisplay.of(content));
63+
return this;
64+
}
65+
66+
public Locale locale() {
67+
return container.locale();
68+
}
69+
70+
public TextDisplayContainer locale(Locale locale) {
71+
container.locale(locale);
72+
return this;
73+
}
74+
75+
public TextDisplayContainer locale(DiscordLocale locale) {
76+
container.locale(locale);
77+
return this;
78+
}
79+
80+
public Collection<TextDisplay> textDisplays() {
81+
return container.getComponents().stream().map(TextDisplay.class::cast).toList();
82+
}
83+
84+
@Override
85+
public DataObject toData() {
86+
DataObject json = DataObject.empty().put("type", getType().getKey()).put("content", getContent());
87+
if (getUniqueId() >= 0) {
88+
json.put("id", getUniqueId());
89+
}
90+
return json;
91+
}
92+
93+
@Override
94+
public String getContent() {
95+
return container.getComponents().stream()
96+
.map(TextDisplay.class::cast)
97+
.map(TextDisplay::getContent)
98+
.collect(Collectors.joining("\n"));
99+
}
100+
101+
@Override
102+
public TextDisplayContainer withContent(String content) {
103+
return withContent(TextDisplay.of(content));
104+
}
105+
106+
public TextDisplayContainer withContent(TextDisplay textDisplay) {
107+
container = container.withComponents(textDisplay);
108+
return this;
109+
}
110+
111+
@Override
112+
public TextDisplayContainer withUniqueId(int uniqueId) {
113+
return (TextDisplayContainer) super.withUniqueId(uniqueId);
114+
}
115+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/// Collection of utility classes for components V2. You can think of these like an ui component library.
2+
package io.github.kaktushose.jdac.components;

0 commit comments

Comments
 (0)