Skip to content

Commit

Permalink
Fix + Refacto champs with not enough datas + champ icon on each item …
Browse files Browse the repository at this point in the history
…list

Signed-off-by: Olivier MARY <olivier@omary.fr>
  • Loading branch information
OlivierMary committed Jun 30, 2020
1 parent b77c449 commit 7fa4a6b
Show file tree
Hide file tree
Showing 14 changed files with 407 additions and 470 deletions.
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,8 @@ Set summoner spell for calculated position
## Improvement
- Clean Generated notification in Lcu
- Change App name for windows Task Manager it's the jdk name ==> `-Dname` not working
- Make a screen with all champ icons + all possible position to send datas
- `/lol-perks/v1/inventory` to check how many page Yuumi can create ==> reduce delete > create > delete > create ...
- Make a screen with all champ icons

## Refactor
- DTO for yuumi tools and not from ugg + parse ugg -> new dto
- Not dependent of com.github.stirante:lol-client-java-api

## Fix
- On new caches somes datas are empty the first day => change the way of parsing datas may solve this.

162 changes: 127 additions & 35 deletions src/main/kotlin/fr/omary/lol/yuumi/Application.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package fr.omary.lol.yuumi

import fr.omary.lol.yuumi.models.Champion
import fr.omary.lol.yuumi.models.Rank
import fr.omary.lol.yuumi.models.YPosition
import fr.omary.lol.yuumi.models.Zone
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClients
import java.awt.*
import java.awt.AWTException
import java.awt.Image
import java.awt.SystemTray
import java.awt.TrayIcon
import java.awt.event.ActionListener
import java.awt.event.ItemEvent
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.io.File
import java.io.FileReader
import java.io.FileWriter
Expand All @@ -28,11 +35,14 @@ private val loading = createImage("images/loading.gif", "tray icon")
private val automaticDisabled = createImage("images/automaticDisabled.png", "tray icon")
private val trayIcon = TrayIcon(waiting.image)
private val messages: MutableList<Pair<LocalDateTime, String>> = mutableListOf()
private var champMenu = Menu("Send Synchronized Champion")
private var champMenuAtoG = Menu("[A-G]")
private var champMenuHtoM = Menu("[H-M]")
private var champMenuNtoS = Menu("[N-S]")
private var champMenuTtoZ = Menu("[T-Z]")
private var champMenu = JMenu("Send Champion")
private var rankMenu = JMenu("Rank")
private var zoneMenu = JMenu("Zone")
private var champMenuAtoF = JMenu("[A-F]")
private var champMenuGtoK = JMenu("[G-K]")
private var champMenuNtoQ = JMenu("[L-Q]")
private var champMenuRtoS = JMenu("[R-S]")
private var champMenuTtoZ = JMenu("[T-Z]")
private const val yuumi = "Yuumi"
private const val defaultToolTip = "$yuumi is ready"
private const val waitingMessage = "Yuumi : Waiting LoL client to connect"
Expand All @@ -42,11 +52,14 @@ private val yuumiTempDir = "${tmpDir}/yuumi"
private val yuumiConfig = "$yuumiTempDir/config"
val rankedDirectory = File("$yuumiTempDir/ranked")
val aramDirectory = File("$yuumiTempDir/aram")
val squareDirectory = File("$yuumiTempDir/square")
val lastSync: File? = File("$yuumiTempDir/lastSync")
var lastSyncDate: String = "Never"
var sync = MenuItem("$lastSyncMessage $lastSyncDate")
var sync = JMenuItem("$lastSyncMessage $lastSyncDate")
var automatic: Boolean = true
var currentState = waiting
var currentZone: Zone = Zone.ALL
var currentRank: Rank = Rank.PLATINE_PLUS
val httpclient: CloseableHttpClient = HttpClients.createDefault()

fun main() {
Expand All @@ -71,13 +84,21 @@ fun loadConfig() {
automatic = properties["automatic"].toString().toBoolean()
}
setAutomaticIcon()
if (properties["zone"] != null) {
currentZone = Zone.values().first { z -> z.keyUgg == properties["zone"].toString().toInt() }
}
if (properties["rank"] != null) {
currentRank = Rank.values().first { r -> r.keyUgg == properties["rank"].toString().toInt() }
}
}
}

fun storeConfig() {
val properties = Properties()
properties["sendNotifications"] = sendNotifications.toString()
properties["automatic"] = automatic.toString()
properties["zone"] = currentZone.keyUgg.toString()
properties["rank"] = currentRank.keyUgg.toString()
properties.store(FileWriter(yuumiConfig), "Store Properties")
}

Expand Down Expand Up @@ -108,6 +129,7 @@ private fun refreshLastSyncDate() {
private fun createTempsDirs() {
rankedDirectory.mkdirs()
aramDirectory.mkdirs()
squareDirectory.mkdirs()
}


Expand All @@ -116,36 +138,63 @@ private fun createAndShowGUI() {
println("SystemTray is not supported")
return
}
val popupMenu = PopupMenu()
val popupMenu = JPopupMenu()

val tray = SystemTray.getSystemTray()

val aboutItem = MenuItem("About")
val history = MenuItem("History")
val aboutItem = JMenuItem("About")
val history = JMenuItem("History")

val optionNotifications = CheckboxMenuItem("Enable Notifications")
val optionNotifications = JCheckBoxMenuItem("Enable Notifications")
optionNotifications.state = sendNotifications
val automaticSelection = CheckboxMenuItem("Automatic selection")
val automaticSelection = JCheckBoxMenuItem("Automatic selection")
automaticSelection.state = automatic
val exitItem = MenuItem("Exit")
val exitItem = JMenuItem("Exit")

popupMenu.add(aboutItem)
popupMenu.addSeparator()
popupMenu.add(optionNotifications)
popupMenu.add(automaticSelection)
popupMenu.add(history)
popupMenu.addSeparator()
popupMenu.add(sync)
popupMenu.add(zoneMenu)
popupMenu.add(rankMenu)
popupMenu.addSeparator()
popupMenu.add(champMenu)
popupMenu.addSeparator()
popupMenu.add(exitItem)

champMenu.add(champMenuAtoG)
champMenu.add(champMenuHtoM)
champMenu.add(champMenuNtoS)
champMenu.add(champMenuAtoF)
champMenu.add(champMenuGtoK)
champMenu.add(champMenuNtoQ)
champMenu.add(champMenuRtoS)
champMenu.add(champMenuTtoZ)

trayIcon.popupMenu = popupMenu
Zone.values().sortedBy { zone -> zone.title }.forEach { zone -> zoneMenu.add(generateZoneMenu(zone)) }
Rank.values().sortedBy { rank -> rank.title }.forEach { rank -> rankMenu.add(generateRankMenu(rank)) }

updateOptionsMenu()


trayIcon.addMouseListener(object : MouseAdapter() {
override fun mouseReleased(e: MouseEvent) {
maybeShowPopup(e)
}

override fun mousePressed(e: MouseEvent) {
maybeShowPopup(e)
}

private fun maybeShowPopup(e: MouseEvent) {
if (e.isPopupTrigger()) {
popupMenu.setLocation(e.getX(), e.getY() - 250)
popupMenu.setInvoker(popupMenu)
popupMenu.setVisible(true)
}
}
})

trayIcon.isImageAutoSize = true
trayIcon.toolTip = waitingMessage
try {
Expand All @@ -172,9 +221,7 @@ private fun createAndShowGUI() {
}

sync.addActionListener {
runBlocking {
forceReSyncChampsDatas()
}
forceReSyncChampsDatas()
}

optionNotifications.addItemListener { e ->
Expand All @@ -194,6 +241,12 @@ private fun createAndShowGUI() {
}
}

private fun updateOptionsMenu() {
zoneMenu.label = "Zone [ ${currentZone.title} ]"
rankMenu.label = "Rank [ ${currentRank.title} ]"
storeConfig()
}

fun automaticReSyncIfDataTooOld() {
if (lastSyncDate == "Never" || LocalDateTime.now().isAfter(LocalDateTime.parse(lastSyncDate).plusDays(1))) {
println("Force resync")
Expand All @@ -203,9 +256,11 @@ fun automaticReSyncIfDataTooOld() {
}

fun forceReSyncChampsDatas() {
startLoading("Retrieve all champions assets")
rankedDirectory.list()?.forEach { File("$rankedDirectory/$it").delete() }
aramDirectory.list()?.forEach { File("$aramDirectory/$it").delete() }
getChampionList() // reset cache of champions
squareDirectory.list()?.forEach { File("$squareDirectory/$it").delete() }
getChampionList(true) // reset cache of champions
lastSync?.writeText(LocalDateTime.now().toString())
refreshLastSyncDate()
refreshChampionList()
Expand All @@ -232,6 +287,17 @@ private fun showHistory() {
fun createImage(path: String, description: String?): ImageIcon =
ImageIcon(Thread.currentThread().contextClassLoader.getResource(path), description)

fun createImage(file: File): ImageIcon = resizeIcon(ImageIcon(file.path))

fun createImage(path: String): ImageIcon =
resizeIcon(ImageIcon(Thread.currentThread().contextClassLoader.getResource(path)))

private fun resizeIcon(i: ImageIcon): ImageIcon {
val image: Image = i.image
val newimg = image.getScaledInstance(20, 20, Image.SCALE_SMOOTH)
return ImageIcon(newimg)
}

fun sendSystemNotification(message: String, level: String) {
if (sendNotifications) {
messages.add(Pair(LocalDateTime.now(), message))
Expand Down Expand Up @@ -283,37 +349,63 @@ fun ready() {
}

fun refreshChampionList() {
champMenuAtoG.removeAll()
champMenuHtoM.removeAll()
champMenuNtoS.removeAll()
champMenuAtoF.removeAll()
champMenuGtoK.removeAll()
champMenuNtoQ.removeAll()
champMenuRtoS.removeAll()
champMenuTtoZ.removeAll()
getChampionList().forEach {
when (it.name.first()) {
in 'A'..'G' -> champMenuAtoG.add(generateItemMenu(it))
in 'H'..'M' -> champMenuHtoM.add(generateItemMenu(it))
in 'N'..'S' -> champMenuNtoS.add(generateItemMenu(it))
in 'T'..'Z' -> champMenuTtoZ.add(generateItemMenu(it))
in 'A'..'F' -> champMenuAtoF.add(generateChampionMenu(it))
in 'G'..'K' -> champMenuGtoK.add(generateChampionMenu(it))
in 'L'..'Q' -> champMenuNtoQ.add(generateChampionMenu(it))
in 'R'..'S' -> champMenuRtoS.add(generateChampionMenu(it))
in 'T'..'Z' -> champMenuTtoZ.add(generateChampionMenu(it))
}
GlobalScope.launch { processChampion(it) }
}
}

fun generateChampPosition(champ: Champion, position: String): MenuItem {
val menuItem = MenuItem(position)
fun generateChampPosition(champ: Champion, position: YPosition): JMenuItem {
val menuItem = JMenuItem(position.title)
menuItem.icon = createImage("images/${position.iconName}")
val listener = ActionListener {
GlobalScope.launch {
sendChampionPostion(champ, position.toLowerCase(), getCurrentGameMode().await())
sendChampionPostion(champ, position, getCurrentGameMode().await())
}
}
menuItem.addActionListener(listener)
return menuItem
}


fun generateItemMenu(champ: Champion): MenuItem {
val menuChamp = Menu(champ.name)
listOf("Top", "Jungle", "Middle", "Bottom", "Utility", "ARAM").forEach {
fun generateChampionMenu(champ: Champion): JMenu {
val menuChamp = JMenu(champ.name)
val champFile = File("$squareDirectory/${champ.key}.png")
if (champFile.exists()) {
menuChamp.icon = createImage(champFile)
}
YPosition.values().forEach {
menuChamp.add(generateChampPosition(champ, it))
}
return menuChamp
}

fun generateZoneMenu(zon: Zone): JMenuItem {
val menuZone = JMenuItem(zon.title)
menuZone.addActionListener {
currentZone = zon
updateOptionsMenu()
}
return menuZone
}

fun generateRankMenu(ran: Rank): JMenuItem {
val menuRank = JMenuItem(ran.title)
menuRank.addActionListener {
currentRank = ran
updateOptionsMenu()
}
return menuRank
}

2 changes: 1 addition & 1 deletion src/main/kotlin/fr/omary/lol/yuumi/LcuService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kotlinx.coroutines.*
private val api = ClientApi()
private var socket: ClientWebSocket? = null

fun apiIsConnected():Boolean = api.isConnected
fun apiIsConnected(): Boolean = api.isConnected

fun startYuumi() {
println("Waiting for client connect.")
Expand Down
39 changes: 25 additions & 14 deletions src/main/kotlin/fr/omary/lol/yuumi/RiotService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,54 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.apache.http.client.methods.HttpGet
import org.apache.http.util.EntityUtils
import java.io.File
import java.io.StringReader
import java.nio.file.Files

const val ARAM_MAP = "HA"
const val SR_MAP = "SR"
val ARAM = LoLMap(12, "HA")
val SR = LoLMap(11, "SR")

private var championList = listOf<Champion>()
private var mapList = listOf(LoLMap(12,ARAM_MAP), LoLMap(11,SR_MAP))

fun getRiotVersion(): Deferred<String> = GlobalScope.async {
fun getRiotVersionAsync(): Deferred<String> = GlobalScope.async {
val jsonVersion = EntityUtils.toString(
httpclient.execute(HttpGet("https://ddragon.leagueoflegends.com/api/versions.json")).entity
)
Klaxon().parseArray<String>(jsonVersion)?.get(0)!!
}

fun getChampionList(): List<Champion> {
if (championList.isEmpty()) {
fun getChampionList(force: Boolean = false): List<Champion> {
if (force || championList.isEmpty()) {
runBlocking {
championList = GlobalScope.async {
val championsJson = EntityUtils.toString(
httpclient.execute(HttpGet("https://ddragon.leagueoflegends.com/cdn/${getRiotVersion().await()}/data/en_US/champion.json")).entity
httpclient.execute(HttpGet("https://ddragon.leagueoflegends.com/cdn/${getRiotVersionAsync().await()}/data/en_US/champion.json")).entity
)

val datas = Klaxon().parseJsonObject(StringReader(championsJson)).get("data") as JsonObject
datas.entries.map { Champion(((it.value as JsonObject).get("key") as String).toInt(), ((it.value as JsonObject).get("name") as String)) }.toList()
datas.entries.map {
Champion(
((it.value as JsonObject).get("key") as String).toInt(),
((it.value as JsonObject).get("name") as String),
((it.value as JsonObject).get("id")) as String
)
}.toList()
}.await()
championList.forEach { champion ->
val champFile = File("$squareDirectory/${champion.key}.png")
if (!champFile.exists()) {
Files.copy(
httpclient.execute(HttpGet("https://ddragon.leagueoflegends.com/cdn/${getRiotVersionAsync().await()}/img/champion/${champion.key}.png")).entity.content,
champFile.toPath()
)
}
}
}
}
return championList.sortedBy { champion -> champion.name }
}

fun getMapsList(): List<LoLMap> {
return mapList
return championList.sortedBy { champion -> champion.name }
}



fun main() {
runBlocking {
getChampionList().forEach { println(it) }
Expand Down
Loading

0 comments on commit 7fa4a6b

Please sign in to comment.