1 package org
.libreoffice
;
3 import android
.graphics
.Color
;
4 import android
.graphics
.Rect
;
5 import com
.google
.android
.material
.bottomsheet
.BottomSheetBehavior
;
6 import androidx
.recyclerview
.widget
.GridLayoutManager
;
7 import androidx
.recyclerview
.widget
.RecyclerView
;
8 import android
.view
.View
;
9 import android
.widget
.AdapterView
;
10 import android
.widget
.ArrayAdapter
;
11 import android
.widget
.Button
;
12 import android
.widget
.ImageButton
;
13 import android
.widget
.LinearLayout
;
14 import android
.widget
.RelativeLayout
;
15 import android
.widget
.Spinner
;
17 import org
.json
.JSONArray
;
18 import org
.json
.JSONException
;
19 import org
.json
.JSONObject
;
21 import java
.util
.ArrayList
;
23 public class FontController
implements AdapterView
.OnItemSelectedListener
{
25 /** -1 as value in ".uno:Color" et al. means "automatic color"/no color set. */
26 private static final int COLOR_AUTO
= -1;
28 private boolean mFontNameSpinnerSet
= false;
29 private boolean mFontSizeSpinnerSet
= false;
30 private final LibreOfficeMainActivity mActivity
;
31 private final ArrayList
<String
> mFontList
= new ArrayList
<>();
32 private final ArrayList
<String
> mFontSizes
= new ArrayList
<>();
34 private String mCurrentFontSelected
= null;
35 private String mCurrentFontSizeSelected
= null;
37 public FontController(LibreOfficeMainActivity activity
) {
40 private BottomSheetBehavior colorPickerBehavior
;
41 private BottomSheetBehavior backColorPickerBehavior
;
42 private BottomSheetBehavior toolBarBottomBehavior
;
43 private ColorPickerAdapter colorPickerAdapter
;
44 private ColorPickerAdapter backColorPickerAdapter
;
46 final ColorPaletteListener colorPaletteListener
= new ColorPaletteListener() {
48 public void applyColor(int color
) {
49 sendFontColorChange(color
, false);
53 public void updateColorPickerPosition(int color
) {
54 if (colorPickerAdapter
== null) {
57 if (color
== COLOR_AUTO
) {
58 colorPickerAdapter
.unselectColors();
59 changeFontColorBoxColor(Color
.TRANSPARENT
);
62 final int colorWithAlpha
= color
| 0xFF000000;
63 colorPickerAdapter
.findSelectedTextColor(colorWithAlpha
);
64 changeFontColorBoxColor(colorWithAlpha
);
68 final ColorPaletteListener backColorPaletteListener
= new ColorPaletteListener() {
70 public void applyColor(int color
) {
71 sendFontBackColorChange(color
, false);
75 public void updateColorPickerPosition(int color
) {
76 if (backColorPickerAdapter
== null) {
79 if (color
== COLOR_AUTO
) {
80 backColorPickerAdapter
.unselectColors();
81 changeFontBackColorBoxColor(Color
.TRANSPARENT
);
84 final int colorWithAlpha
= color
| 0xFF000000;
85 backColorPickerAdapter
.findSelectedTextColor(colorWithAlpha
);
86 changeFontBackColorBoxColor(colorWithAlpha
);
90 private void changeFontColorBoxColor(final int color
){
91 final ImageButton fontColorPickerButton
= mActivity
.findViewById(R
.id
.font_color_picker_button
);
93 LOKitShell
.getMainHandler().post(new Runnable() {
96 fontColorPickerButton
.setBackgroundColor(color
);
101 private void changeFontBackColorBoxColor(final int color
){
102 final ImageButton fontBackColorPickerButton
= mActivity
.findViewById(R
.id
.font_back_color_picker_button
);
104 LOKitShell
.getMainHandler().post(new Runnable() {
107 fontBackColorPickerButton
.setBackgroundColor(color
);
112 private void sendFontChange(String fontName
) {
114 JSONObject json
= new JSONObject();
115 JSONObject valueJson
= new JSONObject();
116 valueJson
.put("type", "string");
117 valueJson
.put("value", fontName
);
118 json
.put("CharFontName.FamilyName", valueJson
);
120 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:CharFontName", json
.toString()));
122 } catch (JSONException e
) {
127 private void sendFontSizeChange(String fontSize
) {
129 JSONObject json
= new JSONObject();
130 JSONObject valueJson
= new JSONObject();
131 valueJson
.put("type", "float");
132 valueJson
.put("value", fontSize
);
133 json
.put("FontHeight.Height", valueJson
);
135 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:FontHeight", json
.toString()));
137 } catch (JSONException e
) {
142 private void sendFontColorChange(int color
, boolean keepAlpha
){
144 JSONObject json
= new JSONObject();
145 JSONObject valueJson
= new JSONObject();
146 valueJson
.put("type", "long");
147 valueJson
.put("value", keepAlpha ? color
: 0x00FFFFFF & color
);
148 json
.put("Color", valueJson
);
150 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:Color", json
.toString()));
151 changeFontColorBoxColor(color
);
153 } catch (JSONException e
) {
159 * 0x00FFFFFF & color operation removes the alpha which is FF,
160 * if we don't remove it, the color value becomes negative which is not recognized by LOK
162 private void sendFontBackColorChange(int color
, boolean keepAlpha
) {
164 JSONObject json
= new JSONObject();
165 JSONObject valueJson
= new JSONObject();
166 valueJson
.put("type", "long");
167 valueJson
.put("value", keepAlpha ? color
: 0x00FFFFFF & color
);
168 if(mActivity
.getTileProvider().isSpreadsheet()){
169 json
.put("BackgroundColor", valueJson
);
170 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:BackgroundColor", json
.toString()));
172 json
.put("CharBackColor", valueJson
);
173 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:CharBackColor", json
.toString()));
176 changeFontBackColorBoxColor(color
);
178 } catch (JSONException e
) {
185 public void onItemSelected(AdapterView
<?
> parent
, View view
, int pos
, long id
) {
186 if (mFontList
.isEmpty() || !mFontNameSpinnerSet
)
188 if (parent
== mActivity
.findViewById(R
.id
.font_name_spinner
)) {
189 String currentFontSelected
= parent
.getItemAtPosition(pos
).toString();
190 if (!currentFontSelected
.equals(mCurrentFontSelected
)) {
191 mCurrentFontSelected
= currentFontSelected
;
192 sendFontChange(mCurrentFontSelected
);
194 } else if (parent
== mActivity
.findViewById(R
.id
.font_size_spinner
)) {
195 String currentFontSizeSelected
= parent
.getItemAtPosition(pos
).toString();
196 if (!currentFontSizeSelected
.equals(mCurrentFontSizeSelected
)) {
197 mCurrentFontSizeSelected
= currentFontSizeSelected
;
198 sendFontSizeChange(mCurrentFontSizeSelected
);
204 public void onNothingSelected(AdapterView parent
) {
208 public void parseJson(String json
) {
212 JSONObject jObject
= new JSONObject(json
);
213 final JSONArray fontNameArray
= jObject
.getJSONArray("FontNames");
214 for (int i
= 0; i
< fontNameArray
.length(); i
++) {
215 mFontList
.add(fontNameArray
.getString(i
));
218 final JSONArray fontSizeArray
= jObject
.getJSONArray("FontSizes");
219 for (int i
= 0; i
< fontSizeArray
.length(); i
++) {
220 mFontSizes
.add(fontSizeArray
.getString(i
));
222 } catch (JSONException e
) {
227 public void setupFontViews() {
228 LOKitShell
.getMainHandler().post(new Runnable() {
230 setupFontNameSpinner();
231 setupFontSizeSpinner();
233 setupBackColorPicker();
238 private void setupFontNameSpinner() {
239 Spinner fontSpinner
= mActivity
.findViewById(R
.id
.font_name_spinner
);
240 ArrayAdapter
<String
> dataAdapter
= new ArrayAdapter
<>(mActivity
, android
.R
.layout
.simple_spinner_item
, mFontList
);
241 dataAdapter
.setDropDownViewResource(android
.R
.layout
.simple_spinner_dropdown_item
);
242 fontSpinner
.setAdapter(dataAdapter
);
245 private void setupFontSizeSpinner() {
246 Spinner fontSizeSpinner
= mActivity
.findViewById(R
.id
.font_size_spinner
);
247 ArrayAdapter
<String
> dataAdapter
= new ArrayAdapter
<>(mActivity
, android
.R
.layout
.simple_spinner_item
, mFontSizes
);
248 dataAdapter
.setDropDownViewResource(android
.R
.layout
.simple_spinner_dropdown_item
);
249 fontSizeSpinner
.setAdapter(dataAdapter
);
252 private void setupColorPicker(){
253 LinearLayout colorPickerLayout
= mActivity
.findViewById(R
.id
.toolbar_color_picker
);
255 RecyclerView recyclerView
= colorPickerLayout
.findViewById(R
.id
.fontColorView
);
256 GridLayoutManager gridLayoutManager
= new GridLayoutManager(mActivity
, 11, GridLayoutManager
.VERTICAL
, true);
257 recyclerView
.setHasFixedSize(true);
258 recyclerView
.setLayoutManager(gridLayoutManager
);
262 RecyclerView recyclerView2
= colorPickerLayout
.findViewById(R
.id
.fontColorViewSub
);
263 GridLayoutManager gridLayoutManager2
= new GridLayoutManager(mActivity
,4);
264 recyclerView2
.setHasFixedSize(true);
265 recyclerView2
.addItemDecoration(new RecyclerView
.ItemDecoration() {
268 public void getItemOffsets(Rect outRect
, View view
, RecyclerView parent
, RecyclerView
.State state
) {
275 recyclerView2
.setLayoutManager(gridLayoutManager2
);
277 ColorPaletteAdapter colorPaletteAdapter
= new ColorPaletteAdapter(mActivity
, colorPaletteListener
);
278 recyclerView2
.setAdapter(colorPaletteAdapter
);
280 this.colorPickerAdapter
= new ColorPickerAdapter(mActivity
, colorPaletteAdapter
, colorPaletteListener
);
281 recyclerView
.setAdapter(colorPickerAdapter
);
282 RelativeLayout fontColorPicker
= mActivity
.findViewById(R
.id
.font_color_picker
);
283 ImageButton fontColorPickerButton
= mActivity
.findViewById(R
.id
.font_color_picker_button
);
284 View
.OnClickListener clickListener
= new View
.OnClickListener(){
286 public void onClick(View view
) {
287 toolBarBottomBehavior
.setState(BottomSheetBehavior
.STATE_COLLAPSED
);
288 colorPickerBehavior
.setState(BottomSheetBehavior
.STATE_EXPANDED
);
289 mActivity
.findViewById(R
.id
.search_toolbar
).setVisibility(View
.GONE
);
292 LinearLayout toolbarBottomLayout
= mActivity
.findViewById(R
.id
.toolbar_bottom
);
293 colorPickerBehavior
= BottomSheetBehavior
.from(colorPickerLayout
);
294 toolBarBottomBehavior
= BottomSheetBehavior
.from(toolbarBottomLayout
);
296 ImageButton pickerGoBackButton
= colorPickerLayout
.findViewById(R
.id
.button_go_back_color_picker
);
297 pickerGoBackButton
.setOnClickListener(new View
.OnClickListener() {
299 public void onClick(View view
) {
300 toolBarBottomBehavior
.setState(BottomSheetBehavior
.STATE_EXPANDED
);
301 colorPickerBehavior
.setState(BottomSheetBehavior
.STATE_COLLAPSED
);
306 fontColorPicker
.setOnClickListener(clickListener
);
307 fontColorPickerButton
.setOnClickListener(clickListener
);
309 final Button autoColorButton
= colorPickerLayout
.findViewById(R
.id
.button_auto_color
);
310 autoColorButton
.setOnClickListener(view
-> {
311 sendFontColorChange(COLOR_AUTO
, true);
315 private void setupBackColorPicker(){
316 LinearLayout backColorPickerLayout
= mActivity
.findViewById(R
.id
.toolbar_back_color_picker
);
318 RecyclerView recyclerView
= backColorPickerLayout
.findViewById(R
.id
.fontColorView
);
319 GridLayoutManager gridLayoutManager
= new GridLayoutManager(mActivity
, 11, GridLayoutManager
.VERTICAL
, true);
320 recyclerView
.setHasFixedSize(true);
321 recyclerView
.setLayoutManager(gridLayoutManager
);
325 RecyclerView recyclerView2
= backColorPickerLayout
.findViewById(R
.id
.fontColorViewSub
);
326 GridLayoutManager gridLayoutManager2
= new GridLayoutManager(mActivity
,4);
327 recyclerView2
.setHasFixedSize(true);
328 recyclerView2
.addItemDecoration(new RecyclerView
.ItemDecoration() {
331 public void getItemOffsets(Rect outRect
, View view
, RecyclerView parent
, RecyclerView
.State state
) {
338 recyclerView2
.setLayoutManager(gridLayoutManager2
);
340 ColorPaletteAdapter colorPaletteAdapter
= new ColorPaletteAdapter(mActivity
, backColorPaletteListener
);
341 recyclerView2
.setAdapter(colorPaletteAdapter
);
343 this.backColorPickerAdapter
= new ColorPickerAdapter(mActivity
, colorPaletteAdapter
, backColorPaletteListener
);
344 recyclerView
.setAdapter(backColorPickerAdapter
);
345 RelativeLayout fontColorPicker
= mActivity
.findViewById(R
.id
.font_back_color_picker
);
346 ImageButton fontColorPickerButton
= mActivity
.findViewById(R
.id
.font_back_color_picker_button
);
347 View
.OnClickListener clickListener
= new View
.OnClickListener(){
349 public void onClick(View view
) {
350 toolBarBottomBehavior
.setState(BottomSheetBehavior
.STATE_COLLAPSED
);
351 backColorPickerBehavior
.setState(BottomSheetBehavior
.STATE_EXPANDED
);
352 mActivity
.findViewById(R
.id
.search_toolbar
).setVisibility(View
.GONE
);
355 LinearLayout toolbarBottomLayout
= mActivity
.findViewById(R
.id
.toolbar_bottom
);
356 backColorPickerBehavior
= BottomSheetBehavior
.from(backColorPickerLayout
);
357 toolBarBottomBehavior
= BottomSheetBehavior
.from(toolbarBottomLayout
);
359 ImageButton pickerGoBackButton
= backColorPickerLayout
.findViewById(R
.id
.button_go_back_color_picker
);
360 pickerGoBackButton
.setOnClickListener(new View
.OnClickListener() {
362 public void onClick(View view
) {
363 toolBarBottomBehavior
.setState(BottomSheetBehavior
.STATE_EXPANDED
);
364 backColorPickerBehavior
.setState(BottomSheetBehavior
.STATE_COLLAPSED
);
369 fontColorPicker
.setOnClickListener(clickListener
);
370 fontColorPickerButton
.setOnClickListener(clickListener
);
372 final Button autoColorButton
= backColorPickerLayout
.findViewById(R
.id
.button_auto_color
);
373 autoColorButton
.setOnClickListener(view
-> {
374 sendFontBackColorChange(COLOR_AUTO
, true);
378 public void selectFont(final String fontName
) {
379 LOKitShell
.getMainHandler().post(new Runnable() {
381 selectFontCurrentThread(fontName
);
386 private void selectFontCurrentThread(String fontName
) {
387 Spinner spinner
= mActivity
.findViewById(R
.id
.font_name_spinner
);
388 if (!mFontNameSpinnerSet
) {
389 spinner
.setOnItemSelectedListener(this);
390 mFontNameSpinnerSet
= true;
393 if (fontName
.equals(mCurrentFontSelected
))
396 int position
= mFontList
.indexOf(fontName
);
397 if (position
!= -1) {
398 mCurrentFontSelected
= fontName
;
399 spinner
.setSelection(position
,false);
403 public void selectFontSize(final String fontSize
) {
404 LOKitShell
.getMainHandler().post(new Runnable() {
406 selectFontSizeCurrentThread(fontSize
);
411 private void selectFontSizeCurrentThread(String fontSize
) {
412 Spinner spinner
= mActivity
.findViewById(R
.id
.font_size_spinner
);
413 if (!mFontSizeSpinnerSet
) {
414 spinner
.setOnItemSelectedListener(this);
415 mFontSizeSpinnerSet
= true;
418 if (fontSize
.equals(mCurrentFontSizeSelected
))
421 int position
= mFontSizes
.indexOf(fontSize
);
422 if (position
!= -1) {
423 mCurrentFontSizeSelected
= fontSize
;
424 spinner
.setSelection(position
, false);