Updated translations
This commit is contained in:
parent
232fa51ea8
commit
914453d051
130 changed files with 27603 additions and 16775 deletions
|
@ -0,0 +1,42 @@
|
|||
package code.name.monkey.retromusic;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.LocaleList;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils;
|
||||
|
||||
public class LanguageContextWrapper extends android.content.ContextWrapper {
|
||||
|
||||
public LanguageContextWrapper(Context base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
public static LanguageContextWrapper wrap(Context context, Locale newLocale) {
|
||||
Resources res = context.getResources();
|
||||
Configuration configuration = res.getConfiguration();
|
||||
|
||||
if (VersionUtils.INSTANCE.hasNougatMR()) {
|
||||
configuration.setLocale(newLocale);
|
||||
|
||||
LocaleList localeList = new LocaleList(newLocale);
|
||||
LocaleList.setDefault(localeList);
|
||||
configuration.setLocales(localeList);
|
||||
|
||||
context = context.createConfigurationContext(configuration);
|
||||
|
||||
} else if (VersionUtils.INSTANCE.hasLollipop()) {
|
||||
configuration.setLocale(newLocale);
|
||||
context = context.createConfigurationContext(configuration);
|
||||
|
||||
} else {
|
||||
configuration.locale = newLocale;
|
||||
res.updateConfiguration(configuration, res.getDisplayMetrics());
|
||||
}
|
||||
|
||||
return new LanguageContextWrapper(context);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.Constants.APP_INSTAGRAM_LINK
|
||||
import code.name.monkey.retromusic.Constants.APP_TELEGRAM_LINK
|
||||
import code.name.monkey.retromusic.Constants.APP_TWITTER_LINK
|
||||
|
@ -106,6 +107,7 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
openSource.setOnClickListener(this)
|
||||
pinterestLink.setOnClickListener(this)
|
||||
bugReportLink.setOnClickListener(this)
|
||||
translators.setOnClickListener(this)
|
||||
}
|
||||
|
||||
override fun onClick(view: View) {
|
||||
|
@ -123,6 +125,7 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
R.id.changelog -> showChangeLogOptions()
|
||||
R.id.openSource -> NavigationUtil.goToOpenSource(this)
|
||||
R.id.bugReportLink -> NavigationUtil.bugReport(this)
|
||||
R.id.translators -> openUrl("");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,8 +144,9 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
|
||||
private fun getAppVersion(): String {
|
||||
return try {
|
||||
val isPro = if (App.isProVersion()) "Pro" else "Free"
|
||||
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
||||
packageInfo.versionName
|
||||
"${packageInfo.versionName} $isPro"
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
"0.0.0"
|
||||
|
@ -156,11 +160,10 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
}
|
||||
|
||||
private fun loadContributors() {
|
||||
val data = assetJsonData
|
||||
val type = object : TypeToken<List<Contributor>>() {
|
||||
|
||||
}.type
|
||||
val contributors = Gson().fromJson<List<Contributor>>(data, type)
|
||||
val contributors = Gson().fromJson<List<Contributor>>(assetJsonData, type)
|
||||
|
||||
val contributorAdapter = ContributorAdapter(contributors)
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
|
|
|
@ -216,7 +216,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
|
|||
if (lastFmAlbum.album.wiki != null) {
|
||||
aboutAlbumText.show()
|
||||
aboutAlbumTitle.show()
|
||||
aboutAlbumTitle.text = String.format("About %s", lastFmAlbum.album.name)
|
||||
aboutAlbumTitle.text = String.format(getString(R.string.about_album_label), lastFmAlbum.album.name)
|
||||
aboutAlbumText.text = lastFmAlbum.album.wiki.content
|
||||
}
|
||||
if (lastFmAlbum.album.listeners.isNotEmpty()) {
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil;
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper;
|
||||
|
@ -308,7 +309,8 @@ public class MainActivity extends AbsSlidingMusicPanelActivity
|
|||
key.equals(PreferenceUtil.TOGGLE_HOME_BANNER) || key.equals(PreferenceUtil.TOGGLE_ADD_CONTROLS) ||
|
||||
key.equals(PreferenceUtil.ALBUM_COVER_STYLE) || key.equals(PreferenceUtil.HOME_ARTIST_GRID_STYLE) ||
|
||||
key.equals(PreferenceUtil.ALBUM_COVER_TRANSFORM) || key.equals(PreferenceUtil.DESATURATED_COLOR) ||
|
||||
key.equals(PreferenceUtil.TAB_TEXT_MODE) || key.equals(PreferenceUtil.LIBRARY_CATEGORIES)
|
||||
key.equals(PreferenceUtil.TAB_TEXT_MODE) || key.equals(PreferenceUtil.LANGUAGE_NAME) ||
|
||||
key.equals(PreferenceUtil.LIBRARY_CATEGORIES)
|
||||
) {
|
||||
postRecreate();
|
||||
}
|
||||
|
@ -768,5 +770,11 @@ public class MainActivity extends AbsSlidingMusicPanelActivity
|
|||
setTitle(R.string.action_search);
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
Locale[] locales = Locale.getAvailableLocales();
|
||||
|
||||
for (Locale l : locales) {
|
||||
Log.d(TAG, "setupToolbar: " + l.toLanguageTag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
|
|||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
protected fun showOverflowMenu() {
|
||||
private fun showOverflowMenu() {
|
||||
}
|
||||
|
||||
protected open fun requestPermissions() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package code.name.monkey.retromusic.activities.base
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
|
@ -17,10 +18,12 @@ import code.name.monkey.appthemehelper.util.ATHUtil
|
|||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.LanguageContextWrapper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import code.name.monkey.retromusic.util.theme.ThemeManager
|
||||
import java.util.*
|
||||
|
||||
abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
|
||||
|
||||
|
@ -35,6 +38,7 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
|
|||
toggleScreenOn()
|
||||
}
|
||||
|
||||
|
||||
private fun updateTheme() {
|
||||
setTheme(ThemeManager.getThemeResValue(this))
|
||||
setDefaultNightMode(ThemeManager.getNightMode(this))
|
||||
|
@ -206,4 +210,11 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
|
|||
}
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
override fun attachBaseContext(newBase: Context?) {
|
||||
val code = PreferenceUtil.getInstance(newBase).languageCode
|
||||
if (code != "auto") {
|
||||
super.attachBaseContext(LanguageContextWrapper.wrap(newBase, Locale(code)))
|
||||
} else super.attachBaseContext(newBase)
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import android.os.Build;
|
|||
import androidx.annotation.IntRange;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
|
||||
|
@ -57,6 +58,7 @@ public class DeviceInfo {
|
|||
private final int versionCode;
|
||||
|
||||
private final String versionName;
|
||||
private final String selectedLang;
|
||||
|
||||
public DeviceInfo(Context context) {
|
||||
PackageInfo packageInfo;
|
||||
|
@ -76,6 +78,7 @@ public class DeviceInfo {
|
|||
baseTheme = PreferenceUtil.getInstance(context).getBaseTheme();
|
||||
nowPlayingTheme = context.getString(PreferenceUtil.getInstance(context).getNowPlayingScreen().getTitleRes());
|
||||
isAdaptive = PreferenceUtil.getInstance(context).getAdaptiveColor();
|
||||
selectedLang = PreferenceUtil.getInstance(context).getLanguageCode();
|
||||
}
|
||||
|
||||
public String toMarkdown() {
|
||||
|
@ -97,6 +100,7 @@ public class DeviceInfo {
|
|||
+ "<tr><td>ABIs</td><td>" + Arrays.toString(abis) + "</td></tr>\n"
|
||||
+ "<tr><td>ABIs (32bit)</td><td>" + Arrays.toString(abis32Bits) + "</td></tr>\n"
|
||||
+ "<tr><td>ABIs (64bit)</td><td>" + Arrays.toString(abis64Bits) + "</td></tr>\n"
|
||||
+ "<tr><td>Language</td><td>" + selectedLang + "</td></tr>\n"
|
||||
+ "</table>\n";
|
||||
}
|
||||
|
||||
|
@ -119,6 +123,8 @@ public class DeviceInfo {
|
|||
+ "ABIs (64bit): " + Arrays.toString(abis64Bits) + "\n"
|
||||
+ "Base theme: " + baseTheme + "\n"
|
||||
+ "Now playing theme: " + nowPlayingTheme + "\n"
|
||||
+ "Adaptive: " + isAdaptive;
|
||||
+ "Adaptive: " + isAdaptive + "\n"
|
||||
+ "System language: " + Locale.getDefault().toLanguageTag() + "\n"
|
||||
+ "In-App Language: " + selectedLang;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package code.name.monkey.retromusic.adapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.model.Contributor
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import code.name.monkey.retromusic.views.RetroShapeableImageView
|
||||
import com.bumptech.glide.Glide
|
||||
|
||||
class TranslatorsAdapter(
|
||||
private var contributors: List<Contributor>
|
||||
) : RecyclerView.Adapter<TranslatorsAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(
|
||||
LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.item_contributor,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val contributor = contributors[position]
|
||||
holder.bindData(contributor)
|
||||
holder.itemView.setOnClickListener {
|
||||
RetroUtil.openUrl(it?.context as Activity, contributors[position].link)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return contributors.size
|
||||
}
|
||||
|
||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val title: TextView = itemView.findViewById(R.id.title)
|
||||
val text: TextView = itemView.findViewById(R.id.text)
|
||||
val image: RetroShapeableImageView = itemView.findViewById(R.id.icon)
|
||||
|
||||
internal fun bindData(contributor: Contributor) {
|
||||
title.text = contributor.name
|
||||
text.text = contributor.summary
|
||||
Glide.with(image.context)
|
||||
.load(contributor.profileImage)
|
||||
.error(R.drawable.ic_account_white_24dp)
|
||||
.placeholder(R.drawable.ic_account_white_24dp)
|
||||
.dontAnimate()
|
||||
.into(image)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,6 +21,8 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.Constants
|
||||
import code.name.monkey.retromusic.Constants.USER_BANNER
|
||||
|
@ -81,8 +83,20 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba
|
|||
.asBitmap()
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.skipMemoryCache(true)
|
||||
.placeholder(R.drawable.ic_person_flat)
|
||||
.error(R.drawable.ic_person_flat)
|
||||
.placeholder(
|
||||
TintHelper.createTintedDrawable(
|
||||
requireContext(),
|
||||
R.drawable.ic_account_white_24dp,
|
||||
ThemeStore.accentColor(requireContext())
|
||||
)
|
||||
)
|
||||
.error(
|
||||
TintHelper.createTintedDrawable(
|
||||
requireContext(),
|
||||
R.drawable.ic_account_white_24dp,
|
||||
ThemeStore.accentColor(requireContext())
|
||||
)
|
||||
)
|
||||
.into(userImage)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import android.view.View
|
|||
import androidx.preference.Preference
|
||||
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.preferences.MaterialListPreference
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
|
@ -26,7 +27,11 @@ import code.name.monkey.retromusic.R
|
|||
|
||||
class OtherSettingsFragment : AbsSettingsFragment() {
|
||||
override fun invalidateSettings() {
|
||||
|
||||
val languagePreference: MaterialListPreference = findPreference("language_name")!!
|
||||
languagePreference.setOnPreferenceChangeListener { _, _ ->
|
||||
requireActivity().recreate()
|
||||
return@setOnPreferenceChangeListener true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
@ -37,5 +42,7 @@ class OtherSettingsFragment : AbsSettingsFragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
val preference: Preference = findPreference("last_added_interval")!!
|
||||
setSummary(preference)
|
||||
val languagePreference: Preference = findPreference("language_name")!!
|
||||
setSummary(languagePreference)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,4 +20,4 @@ class Contributor(
|
|||
val name: String,
|
||||
val summary: String,
|
||||
val link: String, @SerializedName("profile_image") val profileImage: String
|
||||
)
|
||||
)
|
|
@ -23,12 +23,13 @@ import androidx.core.graphics.BlendModeColorFilterCompat
|
|||
import androidx.core.graphics.BlendModeCompat.SRC_IN
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceDialogFragmentCompat
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.extensions.colorControlNormal
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import com.afollestad.materialdialogs.LayoutMode
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
|
||||
import com.afollestad.materialdialogs.WhichButton
|
||||
import com.afollestad.materialdialogs.actions.getActionButton
|
||||
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
||||
|
||||
class MaterialListPreference @JvmOverloads constructor(
|
||||
|
@ -72,7 +73,7 @@ class MaterialListPreferenceDialog : PreferenceDialogFragmentCompat() {
|
|||
val entries = arguments?.getStringArrayList(EXTRA_ENTRIES)
|
||||
val entriesValues = arguments?.getStringArrayList(EXTRA_ENTRIES_VALUES)
|
||||
val position: Int = arguments?.getInt(EXTRA_POSITION) ?: 0
|
||||
materialDialog = MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT))
|
||||
materialDialog = MaterialDialog(requireContext())
|
||||
.title(text = materialListPreference.title.toString())
|
||||
.positiveButton(R.string.set)
|
||||
.cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
||||
|
@ -94,6 +95,8 @@ class MaterialListPreferenceDialog : PreferenceDialogFragmentCompat() {
|
|||
}
|
||||
dismiss()
|
||||
}
|
||||
materialDialog.getActionButton(WhichButton.POSITIVE)
|
||||
.updateTextColor(ThemeStore.accentColor(requireContext()))
|
||||
return materialDialog
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ public final class PreferenceUtil {
|
|||
public static final String SAF_SDCARD_URI = "saf_sdcard_uri";
|
||||
public static final String SONG_SORT_ORDER = "song_sort_order";
|
||||
public static final String SONG_GRID_SIZE = "song_grid_size";
|
||||
public static final String LANGUAGE_NAME = "language_name";
|
||||
private static final String GENRE_SORT_ORDER = "genre_sort_order";
|
||||
private static final String LAST_PAGE = "last_start_page";
|
||||
private static final String BLUETOOTH_PLAYBACK = "bluetooth_playback";
|
||||
|
@ -154,67 +155,36 @@ public final class PreferenceUtil {
|
|||
private static final String ALBUM_GRID_SIZE = "album_grid_size";
|
||||
private static final String ALBUM_GRID_SIZE_LAND = "album_grid_size_land";
|
||||
private static final String SONG_GRID_SIZE_LAND = "song_grid_size_land";
|
||||
|
||||
private static final String ARTIST_GRID_SIZE = "artist_grid_size";
|
||||
|
||||
private static final String ARTIST_GRID_SIZE_LAND = "artist_grid_size_land";
|
||||
|
||||
private static final String ALBUM_COLORED_FOOTERS = "album_colored_footers";
|
||||
|
||||
private static final String SONG_COLORED_FOOTERS = "song_colored_footers";
|
||||
|
||||
private static final String ARTIST_COLORED_FOOTERS = "artist_colored_footers";
|
||||
|
||||
private static final String ALBUM_ARTIST_COLORED_FOOTERS = "album_artist_colored_footers";
|
||||
|
||||
private static final String COLORED_APP_SHORTCUTS = "colored_app_shortcuts";
|
||||
|
||||
private static final String AUDIO_DUCKING = "audio_ducking";
|
||||
|
||||
private static final String LAST_ADDED_CUTOFF = "last_added_interval";
|
||||
|
||||
private static final String LAST_SLEEP_TIMER_VALUE = "last_sleep_timer_value";
|
||||
|
||||
private static final String NEXT_SLEEP_TIMER_ELAPSED_REALTIME = "next_sleep_timer_elapsed_real_time";
|
||||
|
||||
private static final String IGNORE_MEDIA_STORE_ARTWORK = "ignore_media_store_artwork";
|
||||
|
||||
private static final String LAST_CHANGELOG_VERSION = "last_changelog_version";
|
||||
|
||||
private static final String INTRO_SHOWN = "intro_shown";
|
||||
|
||||
private static final String AUTO_DOWNLOAD_IMAGES_POLICY = "auto_download_images_policy";
|
||||
|
||||
private static final String START_DIRECTORY = "start_directory";
|
||||
|
||||
private static final String SYNCHRONIZED_LYRICS_SHOW = "synchronized_lyrics_show";
|
||||
|
||||
private static final String LOCK_SCREEN = "lock_screen";
|
||||
|
||||
private static final String ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order";
|
||||
|
||||
private static final String ARTIST_DETAIL_SONG_SORT_ORDER = "artist_detail_song_sort_order";
|
||||
|
||||
private static final String LYRICS_OPTIONS = "lyrics_tab_position";
|
||||
|
||||
private static final String CHOOSE_EQUALIZER = "choose_equalizer";
|
||||
|
||||
private static final String TOGGLE_SHUFFLE = "toggle_shuffle";
|
||||
|
||||
private static final String SONG_GRID_STYLE = "song_grid_style";
|
||||
|
||||
private static final String TOGGLE_ANIMATIONS = "toggle_animations";
|
||||
|
||||
private static final String LAST_KNOWN_LYRICS_TYPE = "LAST_KNOWN_LYRICS_TYPE";
|
||||
|
||||
private static final String ALBUM_DETAIL_STYLE = "album_detail_style";
|
||||
|
||||
private static final String PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume";
|
||||
|
||||
private static final String NOW_PLAYING_SCREEN = "now_playing_screen";
|
||||
|
||||
private static final String SNOW_FALL_EFFECT = "snow_fall_effect";
|
||||
|
||||
private static final String FILTER_SONG = "filter_song";
|
||||
private static final String TAG = "PreferenceUtil";
|
||||
private static final String EXPAND_NOW_PLAYING_PANEL = "expand_now_playing_panel";
|
||||
|
@ -987,4 +957,8 @@ public final class PreferenceUtil {
|
|||
public boolean isExpandPanel() {
|
||||
return mPreferences.getBoolean(EXPAND_NOW_PLAYING_PANEL, false);
|
||||
}
|
||||
|
||||
public String getLanguageCode() {
|
||||
return mPreferences.getString(LANGUAGE_NAME, "auto");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue