allow using user-provided font

fixes #494
This commit is contained in:
Helium314 2025-01-17 21:47:13 +01:00
parent c581e9601b
commit 9a2009d182
9 changed files with 94 additions and 3 deletions

View file

@ -95,6 +95,7 @@ public class KeyboardView extends View {
@NonNull @NonNull
private final Paint mPaint = new Paint(); private final Paint mPaint = new Paint();
private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics();
protected final Typeface mTypeface;
public KeyboardView(final Context context, final AttributeSet attrs) { public KeyboardView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.keyboardViewStyle); this(context, attrs, R.attr.keyboardViewStyle);
@ -144,6 +145,7 @@ public class KeyboardView extends View {
keyAttr.recycle(); keyAttr.recycle();
mPaint.setAntiAlias(true); mPaint.setAntiAlias(true);
mTypeface = Settings.getInstance().readCustomTypeface();
} }
@Nullable @Nullable
@ -381,7 +383,7 @@ public class KeyboardView extends View {
float labelBaseline = centerY; float labelBaseline = centerY;
final String label = key.getLabel(); final String label = key.getLabel();
if (label != null) { if (label != null) {
paint.setTypeface(key.selectTypeface(params)); paint.setTypeface(mTypeface == null ? key.selectTypeface(params) : mTypeface);
paint.setTextSize(key.selectTextSize(params)); paint.setTextSize(key.selectTextSize(params));
final float labelCharHeight = TypefaceUtils.getReferenceCharHeight(paint); final float labelCharHeight = TypefaceUtils.getReferenceCharHeight(paint);
final float labelCharWidth = TypefaceUtils.getReferenceCharWidth(paint); final float labelCharWidth = TypefaceUtils.getReferenceCharWidth(paint);

View file

@ -798,7 +798,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
final int width = key.getWidth(); final int width = key.getWidth();
final int height = key.getHeight(); final int height = key.getHeight();
paint.setTextAlign(Align.CENTER); paint.setTextAlign(Align.CENTER);
paint.setTypeface(Typeface.DEFAULT); paint.setTypeface(mTypeface == null ? Typeface.DEFAULT : mTypeface);
paint.setTextSize(mLanguageOnSpacebarTextSize); paint.setTextSize(mLanguageOnSpacebarTextSize);
final String customText = Settings.getInstance().getCurrent().mSpaceBarText; final String customText = Settings.getInstance().getCurrent().mSpaceBarText;
final String spaceText; final String spaceText;

View file

@ -156,6 +156,7 @@ class ClipboardHistoryView @JvmOverloads constructor(
val params = KeyDrawParams() val params = KeyDrawParams()
params.updateParams(clipboardLayoutParams.bottomRowKeyboardHeight, keyVisualAttr) params.updateParams(clipboardLayoutParams.bottomRowKeyboardHeight, keyVisualAttr)
Settings.getInstance().readCustomTypeface()?.let { params.mTypeface = it }
setupClipKey(params) setupClipKey(params)
setupBottomRowKeyboard(editorInfo, keyboardActionListener) setupBottomRowKeyboard(editorInfo, keyboardActionListener)

View file

@ -8,6 +8,7 @@ package helium314.keyboard.keyboard.internal;
import android.content.Context; import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.text.TextPaint; import android.text.TextPaint;
import android.text.TextUtils; import android.text.TextUtils;
@ -20,6 +21,7 @@ import androidx.appcompat.widget.AppCompatTextView;
import helium314.keyboard.keyboard.Key; import helium314.keyboard.keyboard.Key;
import helium314.keyboard.latin.R; import helium314.keyboard.latin.R;
import helium314.keyboard.latin.common.StringUtilsKt; import helium314.keyboard.latin.common.StringUtilsKt;
import helium314.keyboard.latin.settings.Settings;
import java.util.HashSet; import java.util.HashSet;
@ -33,6 +35,7 @@ public class KeyPreviewView extends AppCompatTextView {
private final Rect mBackgroundPadding = new Rect(); private final Rect mBackgroundPadding = new Rect();
private static final HashSet<String> sNoScaleXTextSet = new HashSet<>(); private static final HashSet<String> sNoScaleXTextSet = new HashSet<>();
private final Typeface mTypeface;
public KeyPreviewView(final Context context, final AttributeSet attrs) { public KeyPreviewView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0); this(context, attrs, 0);
@ -41,6 +44,7 @@ public class KeyPreviewView extends AppCompatTextView {
public KeyPreviewView(final Context context, final AttributeSet attrs, final int defStyleAttr) { public KeyPreviewView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
setGravity(Gravity.CENTER); setGravity(Gravity.CENTER);
mTypeface = Settings.getInstance().readCustomTypeface();
} }
public void setPreviewVisual(final Key key, final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams) { public void setPreviewVisual(final Key key, final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams) {
@ -54,7 +58,8 @@ public class KeyPreviewView extends AppCompatTextView {
setCompoundDrawables(null, null, null, null); setCompoundDrawables(null, null, null, null);
setTextColor(drawParams.mPreviewTextColor); setTextColor(drawParams.mPreviewTextColor);
setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams)); setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams));
setTypeface(key.selectPreviewTypeface(drawParams)); // wie hier machen?
setTypeface(mTypeface == null ? key.selectPreviewTypeface(drawParams) : mTypeface);
// TODO Should take care of temporaryShiftLabel here. // TODO Should take care of temporaryShiftLabel here.
setTextAndScaleX(key.getPreviewLabel()); setTextAndScaleX(key.getPreviewLabel());
} }

View file

@ -7,6 +7,7 @@ import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Typeface
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -36,12 +37,14 @@ import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.FileUtils import helium314.keyboard.latin.common.FileUtils
import helium314.keyboard.latin.customIconNames import helium314.keyboard.latin.customIconNames
import helium314.keyboard.latin.databinding.ReorderDialogItemBinding import helium314.keyboard.latin.databinding.ReorderDialogItemBinding
import helium314.keyboard.latin.utils.DeviceProtectedUtils
import helium314.keyboard.latin.utils.ResourceUtils import helium314.keyboard.latin.utils.ResourceUtils
import helium314.keyboard.latin.utils.confirmDialog import helium314.keyboard.latin.utils.confirmDialog
import helium314.keyboard.latin.utils.getStringResourceOrName import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.latin.utils.infoDialog import helium314.keyboard.latin.utils.infoDialog
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.io.File
import java.lang.Float.max import java.lang.Float.max
import java.lang.Float.min import java.lang.Float.min
import java.util.* import java.util.*
@ -86,6 +89,12 @@ class AppearanceSettingsFragment : SubScreenFragment() {
loadImage(uri, true, true) loadImage(uri, true, true)
} }
private val fontFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult
val uri = it.data?.data ?: return@registerForActivityResult
saveCustomTypeface(uri)
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.prefs_screen_appearance) addPreferencesFromResource(R.xml.prefs_screen_appearance)
@ -106,6 +115,7 @@ class AppearanceSettingsFragment : SubScreenFragment() {
} }
findPreference<Preference>("custom_background_image")?.setOnPreferenceClickListener { onClickLoadImage(false) } findPreference<Preference>("custom_background_image")?.setOnPreferenceClickListener { onClickLoadImage(false) }
findPreference<Preference>("custom_background_image_landscape")?.setOnPreferenceClickListener { onClickLoadImage(true) } findPreference<Preference>("custom_background_image_landscape")?.setOnPreferenceClickListener { onClickLoadImage(true) }
findPreference<Preference>("custom_font")?.setOnPreferenceClickListener { onClickCustomFont() }
findPreference<Preference>(Settings.PREF_CUSTOM_ICON_NAMES)?.setOnPreferenceClickListener { findPreference<Preference>(Settings.PREF_CUSTOM_ICON_NAMES)?.setOnPreferenceClickListener {
if (needsReload) if (needsReload)
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext())
@ -389,6 +399,44 @@ class AppearanceSettingsFragment : SubScreenFragment() {
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext())
} }
private fun onClickCustomFont(): Boolean {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType("*/*")
val fontFile = Settings.getCustomFontFile(requireContext())
if (fontFile.exists()) {
AlertDialog.Builder(requireContext())
.setTitle(R.string.custom_font)
.setPositiveButton(R.string.load) { _, _ -> fontFilePicker.launch(intent) }
.setNegativeButton(android.R.string.cancel, null)
.setNeutralButton(R.string.delete) { _, _ ->
fontFile.delete()
Settings.clearCachedTypeface()
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext())
}
.show()
} else {
fontFilePicker.launch(intent)
}
return true
}
private fun saveCustomTypeface(uri: Uri) {
val fontFile = Settings.getCustomFontFile(requireContext())
val tempFile = File(DeviceProtectedUtils.getFilesDir(context), "temp_file")
FileUtils.copyContentUriToNewFile(uri, requireContext(), tempFile)
try {
val typeface = Typeface.createFromFile(tempFile)
fontFile.delete()
tempFile.renameTo(fontFile)
Settings.clearCachedTypeface()
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext())
} catch (_: Exception) {
infoDialog(requireContext(), R.string.file_read_error)
tempFile.delete()
}
}
private fun setupScalePrefs(prefKey: String, defaultValue: Float) { private fun setupScalePrefs(prefKey: String, defaultValue: Float) {
val prefs = sharedPreferences val prefs = sharedPreferences
val pref = findPreference(prefKey) as? SeekBarDialogPreference val pref = findPreference(prefKey) as? SeekBarDialogPreference

View file

@ -14,6 +14,7 @@ import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
@ -196,6 +197,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
// static cache for background images to avoid potentially slow reload on every settings reload // static cache for background images to avoid potentially slow reload on every settings reload
private final static Drawable[] sCachedBackgroundImages = new Drawable[4]; private final static Drawable[] sCachedBackgroundImages = new Drawable[4];
private static Typeface sCachedTypeface;
private Map<String, Integer> mCustomToolbarKeyCodes = null; private Map<String, Integer> mCustomToolbarKeyCodes = null;
private Map<String, Integer> mCustomToolbarLongpressCodes = null; private Map<String, Integer> mCustomToolbarLongpressCodes = null;
@ -729,4 +731,25 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
mCustomToolbarLongpressCodes = ToolbarUtilsKt.readCustomLongpressCodes(mPrefs); mCustomToolbarLongpressCodes = ToolbarUtilsKt.readCustomLongpressCodes(mPrefs);
return mCustomToolbarLongpressCodes.get(key.name()); return mCustomToolbarLongpressCodes.get(key.name());
} }
public static File getCustomFontFile(final Context context) {
return new File(DeviceProtectedUtils.getFilesDir(context), "custom_font");
}
@Nullable
public Typeface readCustomTypeface() {
// dammit, dann würde wenns keins gibt bei jedem zugriff gesucht -> 2 variablen nehmen? custom und hasCustom?
// ein clear brauchen wir sowieso on theme changed (und auch triggern wenn man ne font setzt/löscht)
// try/catch!
if (sCachedTypeface == null) {
try {
sCachedTypeface = Typeface.createFromFile(getCustomFontFile(mContext));
} catch (Exception e) { }
}
return sCachedTypeface;
}
public static void clearCachedTypeface() {
sCachedTypeface = null;
}
} }

View file

@ -15,6 +15,7 @@ import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.ShapeDrawable;
@ -155,11 +156,14 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
mToolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar);
mToolbarContainer = findViewById(R.id.toolbar_container); mToolbarContainer = findViewById(R.id.toolbar_container);
final Typeface customTypeface = Settings.getInstance().readCustomTypeface();
for (int pos = 0; pos < SuggestedWords.MAX_SUGGESTIONS; pos++) { for (int pos = 0; pos < SuggestedWords.MAX_SUGGESTIONS; pos++) {
final TextView word = new TextView(context, null, R.attr.suggestionWordStyle); final TextView word = new TextView(context, null, R.attr.suggestionWordStyle);
word.setContentDescription(getResources().getString(R.string.spoken_empty_suggestion)); word.setContentDescription(getResources().getString(R.string.spoken_empty_suggestion));
word.setOnClickListener(this); word.setOnClickListener(this);
word.setOnLongClickListener(this); word.setOnLongClickListener(this);
if (customTypeface != null)
word.setTypeface(customTypeface);
colors.setBackground(word, ColorType.STRIP_BACKGROUND); colors.setBackground(word, ColorType.STRIP_BACKGROUND);
mWordViews.add(word); mWordViews.add(word);
final View divider = inflater.inflate(R.layout.suggestion_divider, null); final View divider = inflater.inflate(R.layout.suggestion_divider, null);

View file

@ -313,6 +313,8 @@
<string name="prefs_bottom_padding_scale">Bottom padding scale</string> <string name="prefs_bottom_padding_scale">Bottom padding scale</string>
<!-- Title of the setting for customizing space bar text --> <!-- Title of the setting for customizing space bar text -->
<string name="prefs_space_bar_text">Custom text on space bar</string> <string name="prefs_space_bar_text">Custom text on space bar</string>
<!-- Title of the setting for adding / removing custom font file -->
<string name="custom_font">Set custom font from file</string>
<!-- Description for English (UK) keyboard subtype [CHAR LIMIT=25] <!-- Description for English (UK) keyboard subtype [CHAR LIMIT=25]
(UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. --> (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. -->
<string name="subtype_en_GB">English (UK)</string> <string name="subtype_en_GB">English (UK)</string>

View file

@ -117,6 +117,12 @@
android:defaultValue="" android:defaultValue=""
android:persistent="true" /> android:persistent="true" />
<Preference
android:key="custom_font"
android:title="@string/custom_font"
android:defaultValue=""
android:persistent="true" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>