minSdkVersion 26

This commit is contained in:
tateisu 2022-08-11 16:51:49 +09:00
parent 03058b25b2
commit 4001c53cba
32 changed files with 149 additions and 436 deletions

View File

@ -170,7 +170,7 @@ dependencies {
kapt 'androidx.annotation:annotation:1.4.0'
// https://firebase.google.com/support/release-notes/android
implementation "com.google.firebase:firebase-messaging:23.0.6"
implementation "com.google.firebase:firebase-messaging:23.0.7"
implementation "org.jetbrains.kotlin:kotlin-reflect"
testImplementation "org.jetbrains.kotlin:kotlin-test"

View File

@ -5,9 +5,7 @@ import android.app.Activity
import android.content.ContentValues
import android.content.Intent
import android.graphics.Bitmap
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.provider.MediaStore
@ -18,7 +16,6 @@ import android.view.View
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import jp.juggler.subwaytooter.Styler.defaultColorIcon
import jp.juggler.subwaytooter.action.accountRemove
import jp.juggler.subwaytooter.api.TootApiClient
@ -117,8 +114,6 @@ class ActAccountSetting : AppCompatActivity(),
private lateinit var viewBinding: ActAccountSettingBinding
private var notificationSoundUri: String? = null
private lateinit var nameInvalidator: NetworkEmojiInvalidator
private lateinit var noteInvalidator: NetworkEmojiInvalidator
private lateinit var defaultTextInvalidator: NetworkEmojiInvalidator
@ -153,20 +148,6 @@ class ActAccountSetting : AppCompatActivity(),
showAcctColor()
}
private val arNotificationSound = ActivityResultHandler(log) { r ->
r.decodeRingtonePickerResult()?.let { uri ->
notificationSoundUri = uri.toString()
saveUIToData()
// Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), uri);
// TextView ringView = (TextView) findViewById(R.id.ringtone);
// ringView.setText(ringtone.getTitle(getApplicationContext()));
// ringtone.setStreamType(AudioManager.STREAM_ALARM);
// ringtone.play();
// SystemClock.sleep(1000);
// ringtone.stop();
}
}
private val arAddAttachment = ActivityResultHandler(log) { r ->
if (r.isNotOk) return@ActivityResultHandler
r.data
@ -217,7 +198,6 @@ class ActAccountSetting : AppCompatActivity(),
prPickHeader.register(this)
arShowAcctColor.register(this)
arNotificationSound.register(this)
arAddAttachment.register(this)
arCameraImage.register(this)
@ -438,8 +418,6 @@ class ActAccountSetting : AppCompatActivity(),
cbConfirmReaction.isChecked = a.confirm_reaction
cbConfirmUnbookmark.isChecked = a.confirm_unbookmark
notificationSoundUri = a.sound_uri
etDefaultText.setText(a.default_text)
etMaxTootChars.setText(a.max_toot_chars.toString())
@ -511,17 +489,10 @@ class ActAccountSetting : AppCompatActivity(),
cbConfirmReaction,
).forEach { it.isEnabledAlpha = enabled }
val enabledOldNotification = enabled && Build.VERSION.SDK_INT < 26
arrayOf(
btnNotificationSoundEdit,
btnNotificationSoundReset,
).forEach { it.isEnabledAlpha = enabledOldNotification }
val enabledNewNotification = enabled && Build.VERSION.SDK_INT >= 26
arrayOf(
btnNotificationStyleEdit,
btnNotificationStyleEditReply,
).forEach { it.isEnabledAlpha = enabledNewNotification }
).forEach { it.isEnabledAlpha = enabled }
}
showVisibility()
@ -574,15 +545,10 @@ class ActAccountSetting : AppCompatActivity(),
account.confirm_reaction = cbConfirmReaction.isChecked
account.confirm_unbookmark = cbConfirmUnbookmark.isChecked
account.sound_uri = notificationSoundUri ?: ""
account.sound_uri = ""
account.default_text = etDefaultText.text.toString()
val num = etMaxTootChars.parseInt()
account.max_toot_chars = if (num != null && num >= 0) {
num
} else {
0
}
account.max_toot_chars = etMaxTootChars.parseInt()?.takeIf { it > 0 } ?: 0
account.movie_max_megabytes = etMovieSizeMax.text.toString().trim()
account.image_max_megabytes = etMediaSizeMax.text.toString().trim()
@ -639,13 +605,6 @@ class ActAccountSetting : AppCompatActivity(),
ActNickname.createIntent(this, account.acct, false),
)
R.id.btnNotificationSoundEdit -> openNotificationSoundPicker()
R.id.btnNotificationSoundReset -> {
notificationSoundUri = ""
saveUIToData()
}
R.id.btnProfileAvatar -> pickAvatarImage()
R.id.btnProfileHeader -> pickHeaderImage()
@ -816,22 +775,6 @@ class ActAccountSetting : AppCompatActivity(),
finish()
}
private fun openNotificationSoundPicker() {
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, R.string.notification_sound)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false)
notificationSoundUri.mayUri()?.let { uri ->
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, uri)
}
val chooser = Intent.createChooser(intent, getString(R.string.notification_sound))
arNotificationSound.launch(chooser)
}
//////////////////////////////////////////////////////////////////////////
private fun initializeProfile() {
@ -1347,18 +1290,6 @@ class ActAccountSetting : AppCompatActivity(),
a.show(this, null)
}
private fun preparePermission(requestCode: Int) {
if (Build.VERSION.SDK_INT >= 23) {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), requestCode
)
return
}
showToast(true, R.string.missing_permission_to_access_media)
}
private fun performAttachment(propName: String) {
try {
state.propName = propName

View File

@ -3,19 +3,16 @@ package jp.juggler.subwaytooter
import android.app.Activity
import android.content.Intent
import android.media.RingtoneManager
import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity
import com.jrummyapps.android.colorpicker.ColorPickerDialog
import com.jrummyapps.android.colorpicker.ColorPickerDialogListener
import jp.juggler.subwaytooter.api.entity.Acct
import jp.juggler.subwaytooter.databinding.ActNicknameBinding
import jp.juggler.subwaytooter.table.AcctColor
import jp.juggler.util.*
import org.jetbrains.anko.backgroundColor
@ -41,17 +38,9 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
}
}
private lateinit var tvPreview: TextView
private lateinit var tvAcct: TextView
private lateinit var etNickname: EditText
private lateinit var btnTextColorEdit: View
private lateinit var btnTextColorReset: View
private lateinit var btnBackgroundColorEdit: View
private lateinit var btnBackgroundColorReset: View
private lateinit var btnSave: View
private lateinit var btnDiscard: View
private lateinit var btnNotificationSoundEdit: Button
private lateinit var btnNotificationSoundReset: Button
private val views by lazy {
ActNicknameBinding.inflate(layoutInflater)
}
private var showNotificationSound = false
private lateinit var acctAscii: String
@ -95,40 +84,25 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
else -> R.string.nickname_and_color
}
)
setContentView(R.layout.act_nickname)
setContentView(views.root)
App1.initEdgeToEdge(this)
Styler.fixHorizontalPadding(findViewById(R.id.llContent))
tvPreview = findViewById(R.id.tvPreview)
tvAcct = findViewById(R.id.tvAcct)
views.btnTextColorEdit.setOnClickListener(this)
views.btnTextColorReset.setOnClickListener(this)
views.btnBackgroundColorEdit.setOnClickListener(this)
views.btnBackgroundColorReset.setOnClickListener(this)
views.btnSave.setOnClickListener(this)
views.btnDiscard.setOnClickListener(this)
etNickname = findViewById(R.id.etNickname)
btnTextColorEdit = findViewById(R.id.btnTextColorEdit)
btnTextColorReset = findViewById(R.id.btnTextColorReset)
btnBackgroundColorEdit = findViewById(R.id.btnBackgroundColorEdit)
btnBackgroundColorReset = findViewById(R.id.btnBackgroundColorReset)
btnSave = findViewById(R.id.btnSave)
btnDiscard = findViewById(R.id.btnDiscard)
views.btnNotificationSoundEdit.setOnClickListener(this)
views.btnNotificationSoundReset.setOnClickListener(this)
etNickname = findViewById(R.id.etNickname)
btnTextColorEdit.setOnClickListener(this)
btnTextColorReset.setOnClickListener(this)
btnBackgroundColorEdit.setOnClickListener(this)
btnBackgroundColorReset.setOnClickListener(this)
btnSave.setOnClickListener(this)
btnDiscard.setOnClickListener(this)
views.btnNotificationSoundEdit.isEnabledAlpha = false
views.btnNotificationSoundReset.isEnabledAlpha = false
btnNotificationSoundEdit = findViewById(R.id.btnNotificationSoundEdit)
btnNotificationSoundReset = findViewById(R.id.btnNotificationSoundReset)
btnNotificationSoundEdit.setOnClickListener(this)
btnNotificationSoundReset.setOnClickListener(this)
val bBefore8 = Build.VERSION.SDK_INT < 26
btnNotificationSoundEdit.isEnabledAlpha = bBefore8
btnNotificationSoundReset.isEnabledAlpha = bBefore8
etNickname.addTextChangedListener(object : TextWatcher {
views.etNickname.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(
s: CharSequence,
start: Int,
@ -152,12 +126,12 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
findViewById<View>(R.id.llNotificationSound).visibility =
if (showNotificationSound) View.VISIBLE else View.GONE
tvAcct.text = acctPretty
views.tvAcct.text = acctPretty
val ac = AcctColor.load(acctAscii, acctPretty)
colorBg = ac.color_bg
colorFg = ac.color_fg
etNickname.setText(ac.nickname)
views.etNickname.setText(ac.nickname)
notificationSoundUri = ac.notification_sound
loadingBusy = false
@ -169,7 +143,7 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
AcctColor(
acctAscii,
acctPretty,
etNickname.text.toString().trim { it <= ' ' },
views.etNickname.text.toString().trim { it <= ' ' },
colorFg,
colorBg,
notificationSoundUri
@ -177,17 +151,17 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
}
private fun show() {
val s = etNickname.text.toString().trim { it <= ' ' }
tvPreview.text = s.notEmpty() ?: acctPretty
tvPreview.textColor = colorFg.notZero() ?: attrColor(R.attr.colorTimeSmall)
tvPreview.backgroundColor = colorBg
val s = views.etNickname.text.toString().trim { it <= ' ' }
views.tvPreview.text = s.notEmpty() ?: acctPretty
views.tvPreview.textColor = colorFg.notZero() ?: attrColor(R.attr.colorTimeSmall)
views.tvPreview.backgroundColor = colorBg
}
override fun onClick(v: View) {
val builder: ColorPickerDialog.Builder
when (v.id) {
R.id.btnTextColorEdit -> {
etNickname.hideKeyboard()
views.etNickname.hideKeyboard()
builder = ColorPickerDialog.newBuilder()
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setAllowPresets(true)
@ -203,7 +177,7 @@ class ActNickname : AppCompatActivity(), View.OnClickListener, ColorPickerDialog
}
R.id.btnBackgroundColorEdit -> {
etNickname.hideKeyboard()
views.etNickname.hideKeyboard()
builder = ColorPickerDialog.newBuilder()
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setAllowPresets(true)

View File

@ -4,7 +4,6 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.text.Editable
@ -302,12 +301,12 @@ class ActPost : AppCompatActivity(),
}
override fun resumeCustomThumbnailTarget(id: String?): PostAttachment? {
id?: return null
return attachmentList.find{ it.attachment?.id?.toString() == id }
id ?: return null
return attachmentList.find { it.attachment?.id?.toString() == id }
}
override fun onPickCustomThumbnail(pa: PostAttachment,src: GetContentResultEntry) {
onPickCustomThumbnailImpl(pa,src)
override fun onPickCustomThumbnail(pa: PostAttachment, src: GetContentResultEntry) {
onPickCustomThumbnailImpl(pa, src)
}
fun initUI() {
@ -327,7 +326,7 @@ class ActPost : AppCompatActivity(),
}
views.root.callbackOnSizeChanged = { _, _, _, _ ->
if (Build.VERSION.SDK_INT >= 24 && isMultiWindowPost) saveWindowSize()
if (isMultiWindowPost) saveWindowSize()
// ビューのw,hはシステムバーその他を含まないので使わない
}

View File

@ -120,7 +120,7 @@ class ActText : AppCompatActivity() {
etText.setText(sv)
// Android 9 以降ではフォーカスがないとsetSelectionできない
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (Build.VERSION.SDK_INT >= 28) {
etText.requestFocus()
etText.hideKeyboard()
}

View File

@ -3,7 +3,6 @@ package jp.juggler.subwaytooter.actmain
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AlertDialog
import jp.juggler.subwaytooter.ActMain
import jp.juggler.subwaytooter.R
@ -106,15 +105,10 @@ fun ActMain.handleOtherUri(uri: Uri): Boolean {
val errorMessage = getString(R.string.cant_handle_uri_of, url)
try {
val queryFlag = if (Build.VERSION.SDK_INT >= 23) {
// Android 6.0以降
// MATCH_DEFAULT_ONLY だと標準の設定に指定されたアプリがあるとソレしか出てこない
// MATCH_ALL を指定すると 以前と同じ挙動になる
PackageManager.MATCH_ALL
} else {
// Android 5.xまでは MATCH_DEFAULT_ONLY でマッチするすべてのアプリを取得できる
PackageManager.MATCH_DEFAULT_ONLY
}
// Android 6.0以降
// MATCH_DEFAULT_ONLY だと標準の設定に指定されたアプリがあるとソレしか出てこない
// MATCH_ALL を指定すると 以前と同じ挙動になる
val queryFlag = PackageManager.MATCH_ALL
// queryIntentActivities に渡すURLは実在しないホストのものにする
val intent = Intent(Intent.ACTION_VIEW, "https://dummy.subwaytooter.club/".toUri())

View File

@ -209,23 +209,6 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
section(R.string.notifications) {
group(R.string.notification_style_before_oreo) {
checkbox(PrefB.bpNotificationSound, R.string.sound) {
enabled = Build.VERSION.SDK_INT < 26
}
checkbox(PrefB.bpNotificationVibration, R.string.vibration) {
enabled = Build.VERSION.SDK_INT < 26
}
checkbox(PrefB.bpNotificationLED, R.string.led) {
enabled = Build.VERSION.SDK_INT < 26
}
sample(R.layout.setting_sample_notification_desc)
}
text(
PrefS.spPullNotificationCheckInterval,
R.string.pull_notification_check_interval,
@ -234,13 +217,13 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
sw(PrefB.bpShowAcctInSystemNotification, R.string.show_acct_in_system_notification)
sw(PrefB.bpSeparateReplyNotificationGroup, R.string.separate_notification_group_for_reply) {
enabled = Build.VERSION.SDK_INT >= 26
}
sw(PrefB.bpSeparateReplyNotificationGroup, R.string.separate_notification_group_for_reply)
sw(PrefB.bpDivideNotification, R.string.divide_notification)
sw(PrefB.bpMisskeyNotificationCheck, R.string.enable_misskey_notification_check)
sample(R.layout.setting_sample_notification_desc)
}
section(R.string.behavior) {
@ -803,7 +786,8 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
colorAlpha(PrefI.ipEventBgColorVote, R.string.vote_polls)
colorAlpha(PrefI.ipEventBgColorStatus, R.string.status)
colorAlpha(PrefI.ipEventBgColorUpdate, R.string.notification_type_update)
colorAlpha(PrefI.ipEventBgColorStatusReference, R.string.notification_type_status_reference)
colorAlpha(PrefI.ipEventBgColorStatusReference,
R.string.notification_type_status_reference)
colorAlpha(PrefI.ipEventBgColorSignUp, R.string.notification_type_signup)
colorAlpha(

View File

@ -1,17 +1,16 @@
package jp.juggler.subwaytooter.dialog
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.*
import android.app.Activity
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.util.CustomShare
import jp.juggler.subwaytooter.util.cn
@ -33,7 +32,7 @@ class DlgAppPicker(
class ListItem(
val icon: Drawable?,
val text: String,
val componentName: String
val componentName: String,
)
val list = ArrayList<ListItem>().apply {
@ -41,11 +40,7 @@ class DlgAppPicker(
val pm = activity.packageManager
val listResolveInfo = pm.queryIntentActivities(
intent,
if (Build.VERSION.SDK_INT >= 23) {
PackageManager.MATCH_ALL
} else {
0
}
PackageManager.MATCH_ALL,
)
for (it in listResolveInfo) {

View File

@ -3,7 +3,6 @@ package jp.juggler.subwaytooter.dialog
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.os.Build
import android.provider.Settings
import android.view.View
import android.view.WindowManager
@ -50,15 +49,8 @@ class DlgDateTime(
this
)
if (Build.VERSION.SDK_INT >= 23) {
timePicker.hour = c.get(Calendar.HOUR_OF_DAY)
timePicker.minute = c.get(Calendar.MINUTE)
} else {
@Suppress("DEPRECATION")
timePicker.currentHour = c.get(Calendar.HOUR_OF_DAY)
@Suppress("DEPRECATION")
timePicker.currentMinute = c.get(Calendar.MINUTE)
}
timePicker.hour = c.get(Calendar.HOUR_OF_DAY)
timePicker.minute = c.get(Calendar.MINUTE)
timePicker.setIs24HourView(
when (Settings.System.getString(activity.contentResolver, Settings.System.TIME_12_24)) {
@ -100,25 +92,15 @@ class DlgDateTime(
}
private fun getTime(): Long {
val y = datePicker.year
val m = datePicker.month
val d = datePicker.dayOfMonth
val h: Int
val j: Int
if (Build.VERSION.SDK_INT >= 23) {
h = timePicker.hour
j = timePicker.minute
} else {
@Suppress("DEPRECATION")
h = timePicker.currentHour
@Suppress("DEPRECATION")
j = timePicker.currentMinute
}
val c = GregorianCalendar.getInstance(TimeZone.getDefault())
c.set(y, m, d, h, j)
c.set(Calendar.SECOND, 0)
c.set(
datePicker.year,
datePicker.month,
datePicker.dayOfMonth,
timePicker.hour,
timePicker.minute,
0,
)
c.set(Calendar.MILLISECOND, 0)
return c.timeInMillis
}

View File

@ -4,7 +4,6 @@ import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
@ -34,21 +33,17 @@ object CheckerNotification {
// val cancelIntent = WorkManager.getInstance(context)
// .createCancelPendingIntent(id)
val builder = if (Build.VERSION.SDK_INT >= 26) {
// Android 8 から、通知のスタイルはユーザが管理することになった
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
// The user-visible description of the channel.
val channel = NotificationHelper.createNotificationChannel(
context,
"PollingForegrounder",
"real-time message notifier",
null,
NotificationManagerCompat.IMPORTANCE_LOW
)
NotificationCompat.Builder(context, channel.id)
} else {
NotificationCompat.Builder(context, "not_used")
}
// Android 8 から、通知のスタイルはユーザが管理することになった
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
// The user-visible description of the channel.
val channel = NotificationHelper.createNotificationChannel(
context,
"PollingForegrounder",
"real-time message notifier",
null,
NotificationManagerCompat.IMPORTANCE_LOW
)
val builder = NotificationCompat.Builder(context, channel.id)
// 通知タップ時のPendingIntent
val clickIntent = Intent(context, ActMain::class.java).apply {
@ -58,10 +53,7 @@ object CheckerNotification {
context,
2,
clickIntent,
PendingIntent.FLAG_UPDATE_CURRENT or when {
Build.VERSION.SDK_INT >= 23 -> PendingIntent.FLAG_IMMUTABLE
else -> 0
}
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// ここは常に白テーマのアイコンと色を使う

View File

@ -1,12 +1,9 @@
package jp.juggler.subwaytooter.notification
import android.annotation.TargetApi
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
@ -14,9 +11,11 @@ import jp.juggler.subwaytooter.ActCallback
import jp.juggler.subwaytooter.EventReceiver
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.pref.PrefB
import jp.juggler.subwaytooter.table.AcctColor
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.util.*
import jp.juggler.util.LogCategory
import jp.juggler.util.encodePercent
import jp.juggler.util.toMutableMap
import jp.juggler.util.toUri
object MessageNotification {
private val log = LogCategory("MessageNotification")
@ -40,7 +39,7 @@ object MessageNotification {
*
*/
fun NotificationManager.removeMessageNotification(account: SavedAccount, tag: String) {
if (Build.VERSION.SDK_INT >= 23 && PrefB.bpDivideNotification()) {
if (PrefB.bpDivideNotification()) {
activeNotifications?.filterNotNull()?.filter {
it.id == NOTIFICATION_ID_MESSAGE && it.tag.startsWith("$tag/")
}?.forEach {
@ -55,7 +54,6 @@ object MessageNotification {
/**
* 表示中のメッセージ通知の一覧
*/
@TargetApi(23)
fun NotificationManager.getMessageNotifications(tag: String) =
activeNotifications?.filterNotNull()?.filter {
it.id == NOTIFICATION_ID_MESSAGE && it.tag.startsWith("$tag/")
@ -72,18 +70,14 @@ object MessageNotification {
) {
log.d("showNotification[${account.acct.pretty}] creating notification(1)")
val builder = if (Build.VERSION.SDK_INT >= 26) {
// Android 8 から、通知のスタイルはユーザが管理することになった
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
val channel = createMessageNotificationChannel(
context,
account,
trackingName
)
NotificationCompat.Builder(context, channel.id)
} else {
NotificationCompat.Builder(context, "not_used")
}
// Android 8 から、通知のスタイルはユーザが管理することになった
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
val channel = createMessageNotificationChannel(
context,
account,
trackingName
)
val builder = NotificationCompat.Builder(context, channel.id)
builder.apply {
@ -98,8 +92,7 @@ object MessageNotification {
}
}.joinToString("&")
val flag = PendingIntent.FLAG_UPDATE_CURRENT or
(if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 0)
val flag = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
PendingIntent.getActivity(
context,
@ -147,54 +140,7 @@ object MessageNotification {
)
}
// Android 8 未満ではチャネルではなく通知に個別にスタイルを設定する
@TargetApi(25)
fun setNotificationSound25(
account: SavedAccount,
builder: NotificationCompat.Builder,
item: NotificationData,
) {
var iv = 0
if (PrefB.bpNotificationSound()) {
var soundUri: Uri? = null
try {
val whoAcct = account.getFullAcct(item.notification.account)
soundUri = AcctColor.getNotificationSound(whoAcct).mayUri()
} catch (ex: Throwable) {
PollingChecker.log.trace(ex)
}
if (soundUri == null) {
soundUri = account.sound_uri.mayUri()
}
var bSoundSet = false
if (soundUri != null) {
try {
builder.setSound(soundUri)
bSoundSet = true
} catch (ex: Throwable) {
PollingChecker.log.trace(ex)
}
}
if (!bSoundSet) {
iv = iv or NotificationCompat.DEFAULT_SOUND
}
}
if (PrefB.bpNotificationVibration()) {
iv = iv or NotificationCompat.DEFAULT_VIBRATE
}
if (PrefB.bpNotificationLED()) {
iv = iv or NotificationCompat.DEFAULT_LIGHTS
}
builder.setDefaults(iv)
}
@TargetApi(26)
fun createMessageNotificationChannel(
private fun createMessageNotificationChannel(
context: Context,
account: SavedAccount,
trackingName: String,
@ -221,12 +167,10 @@ object MessageNotification {
account: SavedAccount,
trackingName: String,
) {
if (Build.VERSION.SDK_INT >= 26) {
val channel = createMessageNotificationChannel(context, account, trackingName)
val intent = Intent("android.settings.CHANNEL_NOTIFICATION_SETTINGS")
intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.id)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
context.startActivity(intent)
}
val channel = createMessageNotificationChannel(context, account, trackingName)
val intent = Intent("android.settings.CHANNEL_NOTIFICATION_SETTINGS")
intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.id)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
context.startActivity(intent)
}
}

View File

@ -1,8 +1,6 @@
package jp.juggler.subwaytooter.notification
import android.annotation.TargetApi
import android.content.Context
import android.os.Build
import androidx.core.app.NotificationCompat
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.TootApiCallback
@ -13,7 +11,6 @@ import jp.juggler.subwaytooter.global.appDispatchers
import jp.juggler.subwaytooter.notification.CheckerWakeLocks.Companion.checkerWakeLocks
import jp.juggler.subwaytooter.notification.MessageNotification.getMessageNotifications
import jp.juggler.subwaytooter.notification.MessageNotification.removeMessageNotification
import jp.juggler.subwaytooter.notification.MessageNotification.setNotificationSound25
import jp.juggler.subwaytooter.notification.MessageNotification.showMessageNotification
import jp.juggler.subwaytooter.pref.PrefB
import jp.juggler.subwaytooter.table.*
@ -467,7 +464,7 @@ class PollingChecker(
first.notification.time_created_at == nt.post_time && first.notification.id == nt.post_id ->
log.d("showNotification[${account.acct.pretty}] id=${first.notification.id} is already shown.")
Build.VERSION.SDK_INT >= 23 && PrefB.bpDivideNotification() -> {
PrefB.bpDivideNotification() -> {
updateNotificationDivided(notificationTag, nt)
nt.updatePost(
first.notification.id,
@ -487,7 +484,6 @@ class PollingChecker(
}
}
@TargetApi(23)
private fun updateNotificationDivided(
notificationTag: String,
nt: NotificationTracking,
@ -538,7 +534,6 @@ class PollingChecker(
builder.setStyle(style)
}
}
if (Build.VERSION.SDK_INT < 26) setNotificationSound25(account, builder, item)
}
}
// リストにない通知は消さない。ある通知をユーザが指で削除した際に他の通知が残ってほしい場合がある
@ -576,7 +571,6 @@ class PollingChecker(
builder.setStyle(style)
}
if (Build.VERSION.SDK_INT < 26) setNotificationSound25(account, builder, first)
}
}
}

View File

@ -4,7 +4,6 @@ import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import jp.juggler.subwaytooter.ActCallback
@ -32,23 +31,19 @@ object ServerTimeoutNotification {
context,
3,
clickIntent,
PendingIntent.FLAG_UPDATE_CURRENT or (if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 0)
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
val builder = if (Build.VERSION.SDK_INT >= 26) {
// Android 8 から、通知のスタイルはユーザが管理することになった
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
val channel = NotificationHelper.createNotificationChannel(
context,
"ErrorNotification",
"Error",
null,
2 /* NotificationManager.IMPORTANCE_LOW */
)
NotificationCompat.Builder(context, channel.id)
} else {
NotificationCompat.Builder(context, "not_used")
}
// Android 8 から、通知のスタイルはユーザが管理することになった
// NotificationChannel を端末に登録しておけば、チャネルごとに管理画面が作られる
val channel = NotificationHelper.createNotificationChannel(
context,
"ErrorNotification",
"Error",
null,
2 /* NotificationManager.IMPORTANCE_LOW */
)
val builder = NotificationCompat.Builder(context, channel.id)
val header = context.getString(R.string.error_notification_title)
val summary = context.getString(R.string.error_notification_summary)

View File

@ -72,20 +72,20 @@ object PrefB {
false
)
val bpNotificationLED = BooleanPref(
"notification_led",
true
)
// val bpNotificationLED = BooleanPref(
// "notification_led",
// true
// )
val bpNotificationSound = BooleanPref(
"notification_sound",
true
)
// val bpNotificationSound = BooleanPref(
// "notification_sound",
// true
// )
val bpNotificationVibration = BooleanPref(
"notification_vibration",
true
)
// val bpNotificationVibration = BooleanPref(
// "notification_vibration",
// true
// )
val bpPostButtonBarTop = BooleanPref(
"post_button_bar_at_top",

View File

@ -11,8 +11,7 @@ import jp.juggler.util.LogCategory
class NetworkStateTracker(
val context: Context,
val onConnectionStateChanged: () -> Unit,
) : ConnectivityManager.NetworkCallback() {
) : ConnectivityManager.NetworkCallback() {
companion object {
private val log = LogCategory("NetworkStateTracker")
@ -27,7 +26,7 @@ class NetworkStateTracker(
}
private val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
as ConnectivityManager
init {
if (Build.VERSION.SDK_INT >= 28) {

View File

@ -4,7 +4,6 @@ import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.provider.Settings
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
@ -88,14 +87,10 @@ class PermissionRequester(
launchMain {
try {
if (Build.VERSION.SDK_INT < 23) {
activity.showToast(true, deniedId)
return@launchMain
}
val shouldShowRational = listNotGranted.any {
shouldShowRequestPermissionRationale(activity, it)
}
if (shouldShowRational && rationalId != 0) {
suspendCancellableCoroutine { cont ->
AlertDialog.Builder(activity)
@ -112,7 +107,10 @@ class PermissionRequester(
.show()
}
}
launcher!!.launch(listNotGranted.toTypedArray())
when (val launcher = launcher) {
null -> error("launcher not registered.")
else -> launcher.launch(listNotGranted.toTypedArray())
}
} catch (ex: Throwable) {
if (ex !is CancellationException) {
activity.showToast(ex, "can't request permissions.")
@ -154,7 +152,9 @@ class PermissionRequester(
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
"package:${activity.packageName}".toUri()
).let { activity.startActivity(it) }
).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}.let { activity.startActivity(it) }
} catch (ex: Throwable) {
activity.showToast(ex, "openAppSetting failed.")
}

View File

@ -4,7 +4,6 @@ import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.OpenableColumns
import android.webkit.MimeTypeMap
import androidx.annotation.RawRes
@ -264,14 +263,12 @@ fun intentGetContent(
// EXTRA_MIME_TYPES は API 19以降。ACTION_GET_CONTENT でも ACTION_OPEN_DOCUMENT でも指定できる
intent.putExtra("android.intent.extra.MIME_TYPES", mimeTypes)
intent.type = when {
mimeTypes.size == 1 -> mimeTypes[0]
intent.type = when (mimeTypes.size) {
1 -> mimeTypes[0]
// On Android 6.0 and above using "video/* image/" or "image/ video/*" type doesn't work
// it only recognizes the first filter you specify.
Build.VERSION.SDK_INT >= 23 -> "*/*"
else -> mimeTypes.joinToString(" ")
else -> "*/*"
}
return Intent.createChooser(intent, caption)

View File

@ -2,7 +2,6 @@ package jp.juggler.util
import android.content.Context
import android.net.Uri
import android.os.Build
import android.text.Spannable
import android.text.SpannableString
import android.text.SpannableStringBuilder
@ -312,12 +311,7 @@ fun <T> Array<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
//fun <T> Sequence<T>.toHashSet() = HashSet<T>().also { it.addAll(this) }
fun defaultLocale(context: Context): Locale =
if (Build.VERSION.SDK_INT >= 24) {
context.resources.configuration.locales[0]
} else {
@Suppress("DEPRECATION")
context.resources.configuration.locale
}
context.resources.configuration.locales[0]
fun Matcher.findOrNull() = if (find()) this else null

View File

@ -201,10 +201,6 @@ private fun rgbToLab(rgb: Int): Triple<Float, Float, Float> {
fun AppCompatActivity.setStatusBarColor(forceDark: Boolean = false) {
window?.apply {
// 古い端末ではナビゲーションバーのアイコン色を設定できないため
// メディアビューア画面ではステータスバーやナビゲーションバーの色を設定しない…
if (forceDark && Build.VERSION.SDK_INT < 26) return
if (Build.VERSION.SDK_INT < 30) {
@Suppress("DEPRECATION")
clearFlags(
@ -238,17 +234,20 @@ private fun AppCompatActivity.setStatusBarColorCompat(@ColorInt c: Int) {
val bit = WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
setSystemBarsAppearance(if (rgbToLab(c).first >= 50f) bit else 0, bit)
}
} else if (Build.VERSION.SDK_INT >= 23) {
} else {
@Suppress("DEPRECATION")
val bit = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
@Suppress("DEPRECATION")
decorView.systemUiVisibility =
if (rgbToLab(c).first >= 50f) {
//Dark Text to show up on your light status bar
decorView.systemUiVisibility or bit
} else {
//Light Text to show up on your dark status bar
decorView.systemUiVisibility and bit.inv()
when {
rgbToLab(c).first >= 50f -> {
//Dark Text to show up on your light status bar
decorView.systemUiVisibility or bit
}
else -> {
//Light Text to show up on your dark status bar
decorView.systemUiVisibility and bit.inv()
}
}
}
}
@ -268,19 +267,17 @@ private fun AppCompatActivity.setNavigationBarColorCompat(@ColorInt c: Int) {
val bit = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
setSystemBarsAppearance(if (rgbToLab(c).first >= 50f) bit else 0, bit)
}
} else if (Build.VERSION.SDK_INT >= 26) {
} else {
@Suppress("DEPRECATION")
val bit = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
@Suppress("DEPRECATION")
decorView.systemUiVisibility = when {
rgbToLab(c).first >= 50f -> {
//Dark Text to show up on your light status bar
//Dark Text to show up on your light status bar
rgbToLab(c).first >= 50f ->
decorView.systemUiVisibility or bit
}
else -> {
//Light Text to show up on your dark status bar
//Light Text to show up on your dark status bar
else ->
decorView.systemUiVisibility and bit.inv()
}
}
}
}

View File

@ -9,11 +9,9 @@
package me.drakeet.support.toast
import android.annotation.SuppressLint
import android.content.Context
import android.content.ContextWrapper
import android.content.res.Resources
import android.os.Build
import android.util.Log
import android.view.Display
import android.view.View
@ -95,19 +93,6 @@ class ToastCompat private constructor(
companion object {
private val log = LogCategory("ToastCompat")
@SuppressLint("DiscouragedPrivateApi")
private fun setContextCompat(view: View?, contextCreator: () -> Context) {
if (view != null && Build.VERSION.SDK_INT == 25) {
try {
val field = View::class.java.getDeclaredField("mContext")
field.isAccessible = true
field[view] = contextCreator()
} catch (ex: Throwable) {
log.trace(ex)
}
}
}
/**
* Make a standard toast that just contains a text view with the text from a resource.
*
@ -136,7 +121,6 @@ class ToastCompat private constructor(
// We cannot pass the SafeToastContext to Toast.makeText() because
// the View will unwrap the base context and we are in vain.
val base = Toast.makeText(context, text, duration)
setContextCompat(base.view) { SafeToastContext(context, base) }
return ToastCompat(context, base)
}
}
@ -152,7 +136,6 @@ class ToastCompat private constructor(
@Deprecated(message = "Custom toast views are deprecated in API level 30.")
override fun setView(view: View) {
base.view = view
setContextCompat(base.view) { SafeToastContext(view.context, base) }
}
@Suppress("DEPRECATION")

View File

@ -617,28 +617,6 @@
<View style="@style/setting_divider" />
<TextView
style="@style/setting_row_label"
android:text="@string/notification_sound_before_oreo" />
<LinearLayout style="@style/setting_row_form">
<Button
android:id="@+id/btnNotificationSoundEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit"
android:textAllCaps="false" />
<Button
android:id="@+id/btnNotificationSoundReset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/reset"
android:textAllCaps="false" />
</LinearLayout>
<View style="@style/setting_divider" />
<TextView

View File

@ -13,8 +13,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:text="@string/preview" />
<TextView
@ -22,10 +22,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingBottom="6dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:paddingTop="6dp"
android:paddingEnd="12dp"
android:paddingBottom="6dp"
android:textSize="20sp"
tools:text="preview..." />
@ -132,7 +132,7 @@
<TextView
style="@style/setting_row_label"
android:text="@string/notification_sound_before_oreo" />
android:text="@string/notification_sound" />
<LinearLayout style="@style/setting_row_form">
@ -171,7 +171,6 @@
android:measureWithLargestChild="true">
<Button
android:id="@+id/btnDiscard"
style="?android:attr/buttonBarButtonStyle"
@ -190,4 +189,4 @@
android:text="@string/save"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -486,10 +486,8 @@
<string name="relative_time_phrase_past">Hi ha %1$d %2$s</string>
<string name="relative_time_phrase_future">Després de %1$d %2$s</string>
<string name="notification_channel_description">Aquest paràmetre serveix per ajustar les notificacions de %1$s</string>
<string name="notification_sound_before_oreo">So de notificació (pre Android 8.0)</string>
<string name="notification_style_after_oreo">Estil de notificacions (Android 8.0+)</string>
<string name="notification_for">Notificacions per %1$s</string>
<string name="notification_style_before_oreo">Estil de notificacions (pre Android 8. Si el teu dispositiu és Android 8.0+, cal que activis el paràmetre a la configuració)</string>
<string name="enquete_was_end">Enquesta finalitzada.</string>
<string name="enquete_voted">S\'ha votat.</string>
<string name="enquete_vote_failed">No s\'ha pogut votar. %1$s</string>

View File

@ -1005,9 +1005,7 @@
<string name="enquete_vote_failed">不能投票. %1$s</string>
<string name="enquete_voted">已投票.</string>
<string name="enquete_was_end">投票结束.</string>
<string name="notification_style_before_oreo">通知方式( Android 8之前. 如果你的设备是 Android 8.0+, 请检查账号设置)</string>
<string name="notification_for">%1$s的通知</string>
<string name="notification_sound_before_oreo">通知声音( Android 8.0之前)</string>
<string name="notification_style_after_oreo">通知方式(Android 8.0+)</string>
<string name="notification_channel_description">此设置用于调整%1$s</string>
<string name="relative_time_phrase_future">%1$d %2$s 之后</string>

View File

@ -934,10 +934,8 @@
<string name="enquete_was_end">Abstimmung beendet.</string>
<string name="enquete_vote_failed">Konnte nicht abstimmen. %1$s</string>
<string name="enquete_voted">Abgestimmt.</string>
<string name="notification_style_before_oreo">Benachrichtigungsstil (vor Android 8. Falls auf deinem Gerät Android 8.0 oder später läuft, sieh bitte in den Konteneinstellungen nach)</string>
<string name="notification_for">Benachrichtigung für %1$s</string>
<string name="notification_style_after_oreo">Benachrichtigungsstil (Android 8.0 und später)</string>
<string name="notification_sound_before_oreo">Benachrichtigungston (vor Android 8.0)</string>
<string name="notification_channel_description">Diese Einstellung legt die Benachrichtigung für %1$s fest</string>
<string name="relative_time_phrase_future">%1$d %2$s später</string>
<string name="relative_time_phrase_past">%1$d %2$s</string>

View File

@ -451,11 +451,9 @@
<string name="relative_time_unit_days">jours</string>
<string name="relative_time_phrase_past">Il y a %1$d %2$s</string>
<string name="relative_time_phrase_future">Dans %1$d %2$s</string>
<string name="notification_sound_before_oreo">Notification sonore (avant Android 8.0)</string>
<string name="notification_style_after_oreo">Style de notifications (Android 8.0+)</string>
<string name="notification_for">Notification for %1$s</string>
<string name="notification_channel_description">Ce paramètre est utilisé pour ajuster les notifications pour %1$s</string>
<string name="notification_style_before_oreo">Style de notification (avant Android 8. Si votre appareil est sous Android 8.0+, veuillez vérifier les paramètres du compte)</string>
<string name="enquete_was_end">Sondage terminé.</string>
<string name="enquete_voted">a voté.</string>
<string name="enquete_vote_failed">Le vote a échoué. %1$s</string>

View File

@ -272,10 +272,8 @@
<string name="relative_time_unit_days">ימים</string>
<string name="relative_time_phrase_future">%1$d %2$s אחר כך</string>
<string name="notification_channel_description">הגדרה זו משמשת להתאמת התראות עבור %1$s</string>
<string name="notification_sound_before_oreo">צליל התראה (לפני אנדרואיד 8.0)</string>
<string name="notification_style_after_oreo">סגנון התראה (אנדרויד 8.0+)</string>
<string name="notification_for">התראה עבור %1$s</string>
<string name="notification_style_before_oreo">סגנון התראה (לפני אנדרויד 8. אם המכשיר שלך הוא אנדרויד 8.0+ , נא לבדוק את הגדרות החשבון)</string>
<string name="enquete_was_end">הסקירה הסתיימה.</string>
<string name="enquete_voted">הצביע.</string>
<string name="enquete_vote_failed">לא ניתן להצביע. %1$s</string>

View File

@ -493,9 +493,7 @@
<string name="notification_on_off_desc">通知のON/OFFはアカウント設定にあります</string>
<string name="notification_option">通知オプション</string>
<string name="notification_sound">通知音</string>
<string name="notification_sound_before_oreo">通知音 (Android 7.x 以下)</string>
<string name="notification_style_after_oreo">通知スタイル(Android 8.x 以降)</string>
<string name="notification_style_before_oreo">通知スタイル(Android 7.x以下。もしお使いのデバイスが8.x以降の場合、アカウント設定から通知スタイルを変更できます)</string>
<string name="notification_tl_font_size">通知TLのフォントの大きさ\n(単位:sp。空欄でデフォルト。アプリ再起動が必要)\n…\n…</string>
<string name="notification_tl_icon_size">通知TLのアイコンの大きさ (単位:dp。デフォルト:24。アプリ再起動が必要)</string>
<string name="notification_type_boost">ブースト</string>

View File

@ -463,10 +463,8 @@
<string name="relative_time_phrase_past">%1$d %2$s</string>
<string name="relative_time_phrase_future">%1$d %2$s 후</string>
<string name="notification_channel_description">이 설정은 %1$s에 대한 알림을 조절하는 데 사용됩니다</string>
<string name="notification_sound_before_oreo">알림 소리 (안드로이드 8.0 이전)</string>
<string name="notification_style_after_oreo">알림 스타일 (안드로이드 8.0 이상)</string>
<string name="notification_for">%1$s에 대한 알림</string>
<string name="notification_style_before_oreo">알림 스타일 (안드로이드 8 이전. 만약 안드로이드 8.0 이상이면 계정 설정을 확인하세요)</string>
<string name="enquete_was_end">설문조사 끝남.</string>
<string name="enquete_voted">투표함.</string>
<string name="enquete_vote_failed">투표할 수 없음. %1$s</string>

View File

@ -372,7 +372,6 @@
<string name="relative_time_phrase_past">%1$d %2$s siden</string>
<string name="relative_time_phrase_future">%1$d %2$s senere</string>
<string name="notification_channel_description">Disse innstillingen brukes for merknad for %1$s</string>
<string name="notification_sound_before_oreo">Merknadslyd (før Android 8.0)</string>
<string name="notification_style_after_oreo">Merknadsstil (Android 8.0 eller senere)</string>
<string name="notification_for">Merknad for %1$s</string>
<string name="enquete_voted">Innsendt.</string>
@ -642,7 +641,6 @@
<string name="format_of_quote_name">Format for \"sitatnavn\" (sett tekst som inneholder %1$s)</string>
<string name="content_sample">(eksempel) Høvdingens kjære squaw får litt pizza i Mexico by.</string>
<string name="remote_profile_warning">Informasjon på andre profilsider kan ikke vises rett. Trykk her for å vise profilen i din nettleser.</string>
<string name="notification_style_before_oreo">Merknadsstil (før Android 8. Hvis din enhet har Android 8.0 eller senere, sjekk kontoinnstilling).</string>
<string name="auto_cw">Skjul lang tekst automatisk (sett linjeopptelling større enn 0 for å skru på dette valget. Programomstart kreves)</string>
<string name="auto_cw_prefix">(Automatisk CW)</string>
<string name="profile_pin">Fest på profil</string>

View File

@ -483,10 +483,8 @@
<string name="relative_time_phrase_past">%1$d %2$s</string>
<string name="relative_time_phrase_future">%1$d %2$s later</string>
<string name="notification_channel_description">This setting is used to adjust notification for %1$s</string>
<string name="notification_sound_before_oreo">Notification sound (pre Android 8.0)</string>
<string name="notification_style_after_oreo">Notification style (Android 8.0+)</string>
<string name="notification_for">Notification for %1$s</string>
<string name="notification_style_before_oreo">Notification style (pre Android 8. if your device is Android 8.0+, please check the account setting)</string>
<string name="enquete_was_end">Enquete ended.</string>
<string name="enquete_voted">Voted.</string>
<string name="enquete_vote_failed">Could not vote. %1$s</string>

View File

@ -2,7 +2,7 @@ buildscript {
ext.jvm_target = "1.8"
ext.min_sdk_version = 21
ext.min_sdk_version = 26
ext.target_sdk_version = 31
ext.compile_sdk_version = 31
@ -29,7 +29,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.1'
classpath 'com.android.tools.build:gradle:7.2.2'
// room google-services
//noinspection GradleDependency