Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiplayer APIv2 #9497

Draft
wants to merge 157 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 140 commits
Commits
Show all changes
157 commits
Select commit Hold shift + click to select a range
8fe9b45
Added new dependencies for networking in the new multiplayer (ktor)
CrsiX Mar 5, 2023
24fdb17
Added some utilities and first structs
CrsiX Mar 6, 2023
6680144
Replace moshi serializer with kotlinx.json, added the API structs
CrsiX Mar 6, 2023
55f49bf
Added the first endpoint implementations, added logging dependency
CrsiX Mar 7, 2023
b88c564
Added the Api core class, fixed enum and response status handling
CrsiX Mar 7, 2023
c741f44
Added a cookie helper to fix authentication flow problems
CrsiX Mar 7, 2023
07d0fb5
Added WebSocket handling and logger functionality, fixed cookie handling
CrsiX Mar 8, 2023
b09ee86
Added support for lobby handling to the Api wrapper
CrsiX Mar 8, 2023
8051c9a
Added friendship handling support to the Api wrapper
CrsiX Mar 8, 2023
39516cb
Updated the API structs
CrsiX Mar 9, 2023
9fbca56
Renamed the old multiplayer handler to start reworking the mechanics
CrsiX Mar 10, 2023
4fbc686
Added WebSocket serializers, structs and message types
CrsiX Mar 10, 2023
dd04aff
Updated the client's implementation of the REST API
CrsiX Mar 10, 2023
1fdb8d0
Added first WebSocket handler
CrsiX Mar 10, 2023
9888bed
Added frame handling, added functional WS sending, added apiVersion t…
CrsiX Mar 10, 2023
8dce89d
Added get all chat rooms endpoint
CrsiX Mar 11, 2023
204e4a3
Added WebSocket data structs
CrsiX Mar 12, 2023
4557dc8
Added game and invite API and structs
CrsiX Mar 18, 2023
8a16d4b
Switched to a non-blocking file storage API
CrsiX Mar 19, 2023
1390c8b
Switch to UUIDs for game identification, added a auth testing function
CrsiX Mar 19, 2023
6a2f1a2
Added the possibility to set specific game IDs during game creation
CrsiX Mar 19, 2023
775d8fd
Split the FileStorage interface to differentiate between game and pre…
CrsiX Mar 19, 2023
a102a8f
Allow setting the username from the multiplayer options dialogue
CrsiX Mar 19, 2023
94a5ebd
Added a file storage emulator as workaround to use API v2
CrsiX Mar 21, 2023
e8f15c3
Added some API helpers and a lot of glue to enable the APIv2 file han…
CrsiX Mar 21, 2023
303cc56
Renamed api package, added ApiVersion enum for easier auto-detection
CrsiX Mar 22, 2023
fb7f056
Added the poll checker, changed the android notification worker poller
CrsiX Mar 22, 2023
6130beb
Fixed a bunch of problems related to error handling
CrsiX Mar 22, 2023
2b8d4d6
Added a lobby browser screen for the APIv2
CrsiX Mar 22, 2023
ffbb661
Improved lobby handling with information in the right side table
CrsiX Mar 22, 2023
0fc201c
Added two new popup types, InfoPopup and RegisterLoginPopup
CrsiX Mar 23, 2023
6bf91a8
Improved OnlineMultiplayer with various new endpoints and concurrency…
CrsiX Mar 23, 2023
0333bb3
Added a separate multiplayer screen using the APIv2
CrsiX Mar 24, 2023
9b403ce
Fixed some API incompatibilities, added getFriends() method
CrsiX Mar 24, 2023
9973a11
Added a helper to open the new multiplayer screen or the register popup
CrsiX Mar 24, 2023
c30b53d
Implemented the friend screen
CrsiX Mar 24, 2023
459c81c
Moved I/O dependency to desktop only, fixed InfoPopus in register popup
CrsiX Mar 24, 2023
1473f04
Rename the Api class to ApiV2Wrapper, added a chat room screen
CrsiX Mar 25, 2023
c51bc17
Improved the chat room screen
CrsiX Mar 26, 2023
db9a81a
Added a button in the WorldScreenTopBar that should open the chat room
CrsiX Mar 26, 2023
aec9904
Fixed RegisterLoginPopup colspan, added key shortcuts
CrsiX Mar 26, 2023
817bb6f
Replaced logging dependency, renamed the endpoint implementations
CrsiX Mar 26, 2023
af0ee11
Dropped the extra logger to remove dependencies, added the APIv2 class
CrsiX Mar 26, 2023
ceffacf
Restructured the project to make ApiV2 class the center
CrsiX Mar 26, 2023
27ce25b
Improved chat handling, added server game detail caching
CrsiX Mar 27, 2023
29abeb4
Align the right control buttons of the NewGameScreen horizontally
CrsiX Mar 27, 2023
0fd7227
Avoid crashing during server checks (e.g. due to network issues)
CrsiX Mar 27, 2023
99708e7
Added a logout button in the multiplayer options tab
CrsiX Mar 28, 2023
69ef74b
Added a generic HTTP request wrapper that can retry requests easily
CrsiX Mar 28, 2023
d5423d3
Added a default handler to retry requests after session refreshing
CrsiX Mar 28, 2023
b6873d7
Updated the API structs based on the new OpenAPI specifications
CrsiX Mar 29, 2023
c37d98b
Switched endpoint implementations to use the new 'request', updated W…
CrsiX Mar 29, 2023
0e5953b
Updated the auth helper, added the UncivNetworkException
CrsiX Mar 29, 2023
93d9327
Fixed some more issues due to refactoring APIv2 handler
CrsiX Mar 29, 2023
f83a77a
Fixed some issues and some minor incompatibilities with the new API
CrsiX Mar 30, 2023
148eee6
Allow storing the result of the register/auth popup persistently
CrsiX Mar 30, 2023
feed93d
Improved lobby handling, added a InfoPopup wrapper
CrsiX Mar 30, 2023
4d921fd
Updated the InfoPopup, added a common interface for map options table
CrsiX Mar 30, 2023
f6882de
Added a ChatMessageList
CrsiX Mar 31, 2023
0681df8
Switch to full JSON for saving APIv2 games instead of minimal
CrsiX Mar 31, 2023
437cc70
Use the ChatMessageList in the ChatRoomScreen
CrsiX Mar 31, 2023
b6c2a82
Added the first version of the LobbyScreen
CrsiX Mar 31, 2023
739e4cf
Opened the NationPickerPopup to use it from other screens as well
CrsiX Mar 31, 2023
2a21a4a
Added a lobby player list and a lobby player
CrsiX Mar 31, 2023
331d881
Added button collections, make use of player lists, fixed various bugs
CrsiX Apr 1, 2023
bd0df40
Implemented the LobbyBrowserTable, added missing API endpoint
CrsiX Apr 1, 2023
ebf5c8c
Added choosing nations for players, fixed kick and add buttons
CrsiX Apr 1, 2023
13975b3
Added a popup that allows creating new APIv2 lobbies (optional password)
CrsiX Apr 2, 2023
ba9e2d3
Created GameDisplayBase for common functionality, introduced GameDisp…
CrsiX Apr 2, 2023
b93a49d
Revert "Created GameDisplayBase for common functionality, introduced …
CrsiX Apr 5, 2023
1ee8dfb
Added new button and various fixes, moved CreateLobbyPopup
CrsiX Apr 5, 2023
0b62347
Fixed login and auth issues in the main menu screen
CrsiX Apr 5, 2023
f411e7f
Added GameListV2, improved the lobby screens
CrsiX Apr 5, 2023
5f80ffa
Added a ChatTable and various fixes to the chat handling
CrsiX Apr 7, 2023
286b719
Added new WebSocket structs for handling invites and friends
CrsiX Apr 10, 2023
f7a3662
Updated the API reference implementation
CrsiX Apr 10, 2023
37ae9d5
Always display InfoPopups forcefully, refreshed the button collection
CrsiX Apr 10, 2023
4e7bdc8
Added a friend table to handle friends and requests
CrsiX Apr 10, 2023
22e3de6
Added GET cache, allowed all WS messages to be Events, added missing …
CrsiX Apr 10, 2023
36694c0
Added lobby invite table
CrsiX Apr 10, 2023
6c5ec58
Added func to dispose and refresh OnlineMultiplayer, only show set us…
CrsiX Apr 11, 2023
dbb8b0e
Updated the lobby screen
CrsiX Apr 11, 2023
811cb8a
Added a handler to start a game from a lobby
CrsiX Apr 11, 2023
6af8718
Updated the chat table and message list to react to incoming messages
CrsiX Apr 12, 2023
659621e
Reworked the ApiV2 class to improve WebSocket handling for every login
CrsiX Apr 12, 2023
d3f6b91
Added small game fetch, fixed lobby start, some smaller fixes
CrsiX Apr 12, 2023
0b00a36
Added friend request canceling and search
CrsiX Apr 12, 2023
05f09c2
Fixed replacing the OnlineMultiplayer instance
CrsiX Apr 12, 2023
599ac30
Added lobby player sorting, fixed duplicate chat messages
CrsiX Apr 12, 2023
78fe724
Enforce multiplayer games when the lobby for V2 games is used
CrsiX Apr 12, 2023
7a1fb22
Improved the LobbyBrowserTable
CrsiX Apr 12, 2023
03f962d
Allow to specify the player and AI civs for new games
CrsiX Apr 13, 2023
059de8b
Change the user ID after logging in to fix later in-game issues
CrsiX Apr 13, 2023
4f9312e
Updated the WorldTopBar's social button, dropped update for LobbyPlay…
CrsiX Apr 13, 2023
f0cc612
Added periodic redrawing of chat messages, added dispose to chat list…
CrsiX Apr 13, 2023
be7c505
Corrected the friend list handling, implemented the social button
CrsiX Apr 14, 2023
fe98ecf
Added serializer class for WebSocket's FriendshipEvent enum
CrsiX Apr 14, 2023
b1ea972
Fixed chat room access and cancelling friendships
CrsiX Apr 15, 2023
a63cf83
Added lobby player event handling
CrsiX Apr 15, 2023
d089ccd
Added a mutex for all changes to the lobby player list
CrsiX Apr 15, 2023
cb5834c
Dropped MultiplayerScreenV2, improved disposing functionality
CrsiX Apr 16, 2023
bc49cab
Improved the social tab and the friend list with the chatting ability
CrsiX Apr 17, 2023
6e1b721
Fixed WebSocket re-connecting, outsourced configs
CrsiX Apr 18, 2023
7b3d45b
Updated the RegisterLoginPopup to ask if the user wants to use the ne…
CrsiX Apr 18, 2023
ddd06ce
Improved the lobby handling, fixed many bugs
CrsiX Apr 20, 2023
2a27ec0
Implemented a self-contained API version check with side-effects
CrsiX Apr 22, 2023
8efbee5
Reworked the multiplayer server check in the multiplayer settings tab
CrsiX Apr 22, 2023
8bea254
Added helper to set the user ID, fixed multiplayer reloading
CrsiX Apr 22, 2023
4c58bc3
Added automatic loading of new games when receiving UpdateGameData ev…
CrsiX Apr 23, 2023
472bec3
Corrected loading of multiplayer games to make auto-loading work smoo…
CrsiX Apr 23, 2023
075d9e8
Added an optional heading for chat message lists
CrsiX Apr 24, 2023
72408a5
Added the SocialMenuScreen, fixed some bugs, improved game start hand…
CrsiX Apr 25, 2023
179c6a9
Only show the new incoming game when the user is expecting it
CrsiX Apr 27, 2023
7437208
Added online multiplayer disposing on app exit
CrsiX Apr 29, 2023
6806789
Fixed various problems with WebSocket connections
CrsiX Apr 30, 2023
b1758ba
Removed refresh button from chat, changed color of auth close button
CrsiX Apr 30, 2023
f96915b
Added BaseScreen handling for some incoming events
CrsiX Apr 30, 2023
8f148d6
Reworked the RegisterLoginPopup to address a bunch of UX issues
CrsiX Apr 30, 2023
9247c44
Don't show kick button for lobby owner, handle network issues during …
CrsiX May 1, 2023
9c1d782
Added auto-reload to lobby browser, added lobby invitation popup
CrsiX May 3, 2023
7a6f23a
Fixed compilation errors due to rebasing regressions
CrsiX May 4, 2023
49af6b1
Added various UX fixes to the lobby screen and the browser
CrsiX May 7, 2023
f1d37d2
Added a first Multiplayer (M) tab for the overview field
CrsiX May 8, 2023
1ec7429
Fixed auto-loading for single player, added GameListV2 updating, fixe…
CrsiX May 9, 2023
642aaf8
Suppress onlineMultiplayer checkbox clicks in game options (APIv2), f…
CrsiX May 10, 2023
6702856
Added English translations for ApiStatusCode, fixed broken APIv1 game…
CrsiX May 10, 2023
3c90e8f
Added auto-scroll to bottom for chat message lists, added some fixes …
CrsiX May 12, 2023
bbb2a26
Fixed subpaths in baseUrl, added server settings button
CrsiX May 12, 2023
c6f01c0
Added WS-based Android turn checker, added a new event channel, fixed…
CrsiX May 14, 2023
1ecbfd4
Refactored the multiplayer turn checker to use its own package
CrsiX May 15, 2023
cefc6cb
Refactored the multiplayer turn checker to move companion code into a…
CrsiX May 18, 2023
30bb0a9
Implemented the APIv2-based listener as TurnChecker V2 (Android)
CrsiX May 20, 2023
c0abe0d
Added a logout hook, implemented ensureConnectedWebSocket
CrsiX May 20, 2023
f68ff4c
Merge branch 'master' into dev
CrsiX May 21, 2023
ef3152e
Switched to use MultiplayerStatusButton for APIv2 games as well
CrsiX May 22, 2023
8d4d7dc
Throttle auto-reconnect for WS on Android in background, added reload…
CrsiX May 22, 2023
118292f
Implemented real pinging with awaiting responses, fixed ping-related …
CrsiX May 28, 2023
a41f7c6
Reworked the SocialMenuScreen into a MultiplayerGameScreen
CrsiX May 31, 2023
489b0fc
Fixed bugs in MultiplayerGameScreen, improved chat message list loading
CrsiX Jun 1, 2023
40316e4
Adapted new getAllChats API, added outstanding friend request list, i…
CrsiX Jun 1, 2023
2a4aaad
Fixed defeated civs not shown in Multiplayer popup
CrsiX Jun 8, 2023
70a8adb
Improved the game list and added a new popup for modifications
CrsiX Jun 9, 2023
f0444f5
Fixed build by moving ktorVersion to buildSrc dir
CrsiX Jun 9, 2023
23d3d0d
Merge branch 'master' into dev
CrsiX Jun 14, 2023
1b95ae1
Fixed broken CreateLobbyPopup, added extra "invalid password" answer
CrsiX Jun 14, 2023
50ada3b
Replaced all wildcard imports with named imports
CrsiX Jun 15, 2023
1db199a
Moved the default message to the ApiStatusCode enum (MPv2)
CrsiX Jun 18, 2023
1810556
Merge branch 'master' into dev
CrsiX Jun 20, 2023
7f7134f
Fixed imports
CrsiX Jun 22, 2023
19445ef
Replaced most runBlocking calls with Concurrency.runBlocking calls
CrsiX Jun 24, 2023
d9f1930
Reworked the APIv2 file storage mechanism
CrsiX Jun 24, 2023
5f258b8
Smaller network improvements, extended docs
CrsiX Jun 25, 2023
c69c9b3
Reworked the access to the api and apiVersion properties, fixed Multi…
CrsiX Jun 25, 2023
c024098
Reworked the LobbyPlayerList and the LobbyScreen sync (mutex behavior)
CrsiX Jun 25, 2023
f03884d
Fixed an instant app crash on Android due to uninitialized UncivGame
CrsiX Jul 6, 2023
5b4c652
Merge branch 'master' into dev
CrsiX Oct 7, 2023
0db9d14
Merge branch 'master' into dev
CrsiX Oct 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions android/src/com/unciv/app/AndroidLauncher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import androidx.core.app.NotificationManagerCompat
import androidx.work.WorkManager
import com.badlogic.gdx.backends.android.AndroidApplication
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration
import com.unciv.app.turncheck.Common
import com.unciv.app.turncheck.WorkerV1
import com.unciv.app.turncheck.WorkerV2
import com.unciv.logic.files.UncivFiles
import com.unciv.logic.multiplayer.ApiVersion
import com.unciv.ui.components.Fonts
import com.unciv.utils.Display
import com.unciv.utils.Log
Expand All @@ -33,7 +37,7 @@ open class AndroidLauncher : AndroidApplication() {
UncivFiles.preferExternalStorage = true

// Create notification channels for Multiplayer notificator
MultiplayerTurnCheckWorker.createNotificationChannels(applicationContext)
Common.createNotificationChannels(applicationContext)

copyMods()

Expand Down Expand Up @@ -70,23 +74,32 @@ open class AndroidLauncher : AndroidApplication() {

override fun onPause() {
val game = this.game!!
if (game.isInitialized
&& game.gameInfo != null
&& game.settings.multiplayer.turnCheckerEnabled
&& game.files.getMultiplayerSaves().any()
) {
MultiplayerTurnCheckWorker.startTurnChecker(
applicationContext, game.files, game.gameInfo!!, game.settings.multiplayer)
if (game.isInitialized) {
if (game.onlineMultiplayer.isInitialized() && game.onlineMultiplayer.apiVersion == ApiVersion.APIv2) {
try {
WorkerV2.start(applicationContext, game.files, game.gameInfo, game.onlineMultiplayer, game.settings.multiplayer)
} catch (e: Exception) {
android.util.Log.e(Common.LOG_TAG, "Error during WorkverV2.start of $this: $e\nMessage: ${e.localizedMessage}\n${e.stackTraceToString()}")
}
} else if (game.gameInfo != null && game.settings.multiplayer.turnCheckerEnabled && game.files.getMultiplayerSaves().any()) {
WorkerV1.startTurnChecker(applicationContext, game.files, game.gameInfo!!, game.settings.multiplayer)
}
}
if (game.onlineMultiplayer.isInitialized() && game.onlineMultiplayer.apiVersion == ApiVersion.APIv2) {
game.onlineMultiplayer.api.disableReconnecting()
}
super.onPause()
}

override fun onResume() {
if (game?.onlineMultiplayer?.isInitialized() == true && game?.onlineMultiplayer?.apiVersion == ApiVersion.APIv2) {
game?.onlineMultiplayer?.api?.enableReconnecting()
}
try {
WorkManager.getInstance(applicationContext).cancelAllWorkByTag(MultiplayerTurnCheckWorker.WORK_TAG)
WorkManager.getInstance(applicationContext).cancelAllWorkByTag(Common.WORK_TAG)
with(NotificationManagerCompat.from(this)) {
cancel(MultiplayerTurnCheckWorker.NOTIFICATION_ID_INFO)
cancel(MultiplayerTurnCheckWorker.NOTIFICATION_ID_SERVICE)
cancel(Common.NOTIFICATION_ID_INFO)
cancel(Common.NOTIFICATION_ID_SERVICE)
}
} catch (ignore: Exception) {
/* Sometimes this fails for no apparent reason - the multiplayer checker failing to
Expand Down
3 changes: 2 additions & 1 deletion android/src/com/unciv/app/CopyToClipboardReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.content.Context
import android.content.Intent
import android.widget.Toast
import com.badlogic.gdx.backends.android.AndroidApplication
import com.unciv.app.turncheck.Common

/**
* This Receiver can be called from an Action on the error Notification shown by MultiplayerTurnCheckWorker.
Expand All @@ -16,7 +17,7 @@ import com.badlogic.gdx.backends.android.AndroidApplication
class CopyToClipboardReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val clipboard: ClipboardManager = context.getSystemService(AndroidApplication.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("exception", intent.getStringExtra(MultiplayerTurnCheckWorker.CLIPBOARD_EXTRA))
val clip = ClipData.newPlainText("exception", intent.getStringExtra(Common.CLIPBOARD_EXTRA))
clipboard.setPrimaryClip(clip)
Toast.makeText(context, context.resources.getString(R.string.Notify_Error_StackTrace_Toast), Toast.LENGTH_SHORT).show()
}
Expand Down
169 changes: 169 additions & 0 deletions android/src/com/unciv/app/turncheck/Common.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package com.unciv.app.turncheck

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.badlogic.gdx.backends.android.AndroidApplication
import com.unciv.app.AndroidLauncher
import com.unciv.app.R
import java.time.Duration
import java.util.UUID

/**
* Collection of common utilities for [WorkerV1] and [WorkerV2]
*/
object Common {
const val WORK_TAG = "UNCIV_MULTIPLAYER_TURN_CHECKER_WORKER"
const val LOG_TAG = "Unciv turn checker"
const val CLIPBOARD_EXTRA = "CLIPBOARD_STRING"
const val NOTIFICATION_ID_SERVICE = 1
const val NOTIFICATION_ID_INFO = 2

// Notification Channels can't be modified after creation.
// Therefore Unciv needs to create new ones and delete previously used ones.
// Add old channel names here when replacing them with new ones below.
private val HISTORIC_NOTIFICATION_CHANNELS = arrayOf("UNCIV_NOTIFICATION_CHANNEL_SERVICE")

internal const val NOTIFICATION_CHANNEL_ID_INFO = "UNCIV_NOTIFICATION_CHANNEL_INFO"
private const val NOTIFICATION_CHANNEL_ID_SERVICE = "UNCIV_NOTIFICATION_CHANNEL_SERVICE_02"

/**
* Notification Channel for 'It's your turn' and error notifications.
*
* This code is necessary for API level >= 26
* API level < 26 does not support Notification Channels
* For more infos: https://developer.android.com/training/notify-user/channels.html#CreateChannel
*/
private fun createNotificationChannelInfo(appContext: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val name = appContext.resources.getString(R.string.Notify_ChannelInfo_Short)
val descriptionText = appContext.resources.getString(R.string.Notify_ChannelInfo_Long)
val importance = NotificationManager.IMPORTANCE_HIGH
val mChannel = NotificationChannel(NOTIFICATION_CHANNEL_ID_INFO, name, importance)
mChannel.description = descriptionText
mChannel.setShowBadge(true)
mChannel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC

val notificationManager = appContext.getSystemService(AndroidApplication.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
}

/**
* Notification Channel for persistent service notification.
*
* This code is necessary for API level >= 26
* API level < 26 does not support Notification Channels
* For more infos: https://developer.android.com/training/notify-user/channels.html#CreateChannel
*/
private fun createNotificationChannelService(appContext: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val name = appContext.resources.getString(R.string.Notify_ChannelService_Short)
val descriptionText = appContext.resources.getString(R.string.Notify_ChannelService_Long)
val importance = NotificationManager.IMPORTANCE_MIN
val mChannel = NotificationChannel(NOTIFICATION_CHANNEL_ID_SERVICE, name, importance)
mChannel.setShowBadge(false)
mChannel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
mChannel.description = descriptionText

val notificationManager = appContext.getSystemService(AndroidApplication.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
}

/**
* The persistent notification is purely for informational reasons.
* It is not technically necessary for the Worker, since it is not a Service.
*/
fun showPersistentNotification(appContext: Context, lastTimeChecked: String, checkPeriod: Duration) {
val flags = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0) or
PendingIntent.FLAG_UPDATE_CURRENT
val pendingIntent: PendingIntent =
Intent(appContext, AndroidLauncher::class.java).let { notificationIntent ->
PendingIntent.getActivity(appContext, 0, notificationIntent, flags)
}

val notification: NotificationCompat.Builder = NotificationCompat.Builder(appContext, NOTIFICATION_CHANNEL_ID_SERVICE)
.setPriority(NotificationManagerCompat.IMPORTANCE_MIN) // it's only a status
.setContentTitle(appContext.resources.getString(R.string.Notify_Persist_Short) + " " + lastTimeChecked)
.setStyle(
NotificationCompat.BigTextStyle()
.bigText(appContext.resources.getString(R.string.Notify_Persist_Long_P1) + " " +
appContext.resources.getString(R.string.Notify_Persist_Long_P2) + " " + checkPeriod.seconds / 60f + " "
+ appContext.resources.getString(R.string.Notify_Persist_Long_P3)
+ " " + appContext.resources.getString(R.string.Notify_Persist_Long_P4)))
.setSmallIcon(R.drawable.uncivnotification)
.setContentIntent(pendingIntent)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setShowWhen(false)

with(NotificationManagerCompat.from(appContext)) {
notify(NOTIFICATION_ID_INFO, notification.build())
}
}

/**
* Create a new notification to inform a user that its his turn in a specfic game
*
* The [game] is a pair of game name and game ID (which is a [UUID]).
*/
fun notifyUserAboutTurn(applicationContext: Context, game: Pair<String, String>) {
Log.i(LOG_TAG, "notifyUserAboutTurn ${game.first} (${game.second})")
val intent = Intent(applicationContext, AndroidLauncher::class.java).apply {
action = Intent.ACTION_VIEW
data = Uri.parse("https://unciv.app/multiplayer?id=${game.second}")
}
val flags = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0) or
PendingIntent.FLAG_UPDATE_CURRENT
val pendingIntent = PendingIntent.getActivity(applicationContext, 0, intent, flags)

val contentTitle = applicationContext.resources.getString(R.string.Notify_YourTurn_Short)
val notification: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL_ID_INFO)
.setPriority(NotificationManagerCompat.IMPORTANCE_HIGH) // people are waiting!
.setContentTitle(contentTitle)
.setContentText(applicationContext.resources.getString(R.string.Notify_YourTurn_Long).replace("[gameName]", game.first))
.setTicker(contentTitle)
// without at least vibrate, some Android versions don't show a heads-up notification
.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
.setLights(Color.YELLOW, 300, 100)
.setSmallIcon(R.drawable.uncivnotification)
.setContentIntent(pendingIntent)
.setCategory(NotificationCompat.CATEGORY_SOCIAL)
.setOngoing(false)

with(NotificationManagerCompat.from(applicationContext)) {
notify(NOTIFICATION_ID_INFO, notification.build())
}
}

/**
* Necessary for Multiplayer Turner Checker, starting with Android Oreo
*/
fun createNotificationChannels(appContext: Context) {
createNotificationChannelInfo(appContext)
createNotificationChannelService(appContext)
destroyOldChannels(appContext)
}

/**
* Notification Channels can't be modified after creation.
* Therefore Unciv needs to create new ones and delete legacy ones.
*/
private fun destroyOldChannels(appContext: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val notificationManager = appContext.getSystemService(AndroidApplication.NOTIFICATION_SERVICE) as NotificationManager
HISTORIC_NOTIFICATION_CHANNELS.forEach {
if (null != notificationManager.getNotificationChannel(it)) {
notificationManager.deleteNotificationChannel(it)
}
}
}
}
Loading