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
;
22 import java
.util
.HashMap
;
23 import java
.util
.Iterator
;
25 public class FontController
implements AdapterView
.OnItemSelectedListener
{
27 /** -1 as value in ".uno:Color" et al. means "automatic color"/no color set. */
28 private static final int COLOR_AUTO
= -1;
30 private boolean mFontNameSpinnerSet
= false;
31 private boolean mFontSizeSpinnerSet
= false;
32 private final LibreOfficeMainActivity mActivity
;
33 private final ArrayList
<String
> mFontList
= new ArrayList
<>();
34 private final ArrayList
<String
> mFontSizes
= new ArrayList
<>();
35 private final HashMap
<String
, ArrayList
<String
>> mAllFontSizes
= new HashMap
<>();
37 private String mCurrentFontSelected
= null;
38 private String mCurrentFontSizeSelected
= null;
40 public FontController(LibreOfficeMainActivity activity
) {
43 private BottomSheetBehavior colorPickerBehavior
;
44 private BottomSheetBehavior backColorPickerBehavior
;
45 private BottomSheetBehavior toolBarBottomBehavior
;
46 private ColorPickerAdapter colorPickerAdapter
;
47 private ColorPickerAdapter backColorPickerAdapter
;
49 final ColorPaletteListener colorPaletteListener
= new ColorPaletteListener() {
51 public void applyColor(int color
) {
52 sendFontColorChange(color
, false);
56 public void updateColorPickerPosition(int color
) {
57 if (colorPickerAdapter
== null) {
60 if (color
== COLOR_AUTO
) {
61 colorPickerAdapter
.unselectColors();
62 changeFontColorBoxColor(Color
.TRANSPARENT
);
65 final int colorWithAlpha
= color
| 0xFF000000;
66 colorPickerAdapter
.findSelectedTextColor(colorWithAlpha
);
67 changeFontColorBoxColor(colorWithAlpha
);
71 final ColorPaletteListener backColorPaletteListener
= new ColorPaletteListener() {
73 public void applyColor(int color
) {
74 sendFontBackColorChange(color
, false);
78 public void updateColorPickerPosition(int color
) {
79 if (backColorPickerAdapter
== null) {
82 if (color
== COLOR_AUTO
) {
83 backColorPickerAdapter
.unselectColors();
84 changeFontBackColorBoxColor(Color
.TRANSPARENT
);
87 final int colorWithAlpha
= color
| 0xFF000000;
88 backColorPickerAdapter
.findSelectedTextColor(colorWithAlpha
);
89 changeFontBackColorBoxColor(colorWithAlpha
);
93 private void changeFontColorBoxColor(final int color
){
94 final ImageButton fontColorPickerButton
= mActivity
.findViewById(R
.id
.font_color_picker_button
);
96 LOKitShell
.getMainHandler().post(new Runnable() {
99 fontColorPickerButton
.setBackgroundColor(color
);
104 private void changeFontBackColorBoxColor(final int color
){
105 final ImageButton fontBackColorPickerButton
= mActivity
.findViewById(R
.id
.font_back_color_picker_button
);
107 LOKitShell
.getMainHandler().post(new Runnable() {
110 fontBackColorPickerButton
.setBackgroundColor(color
);
115 private void sendFontChange(String fontName
) {
117 JSONObject json
= new JSONObject();
118 JSONObject valueJson
= new JSONObject();
119 valueJson
.put("type", "string");
120 valueJson
.put("value", fontName
);
121 json
.put("CharFontName.FamilyName", valueJson
);
123 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:CharFontName", json
.toString()));
125 } catch (JSONException e
) {
130 private void sendFontSizeChange(String fontSize
) {
132 JSONObject json
= new JSONObject();
133 JSONObject valueJson
= new JSONObject();
134 valueJson
.put("type", "float");
135 valueJson
.put("value", fontSize
);
136 json
.put("FontHeight.Height", valueJson
);
138 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:FontHeight", json
.toString()));
140 } catch (JSONException e
) {
145 private void sendFontColorChange(int color
, boolean keepAlpha
){
147 JSONObject json
= new JSONObject();
148 JSONObject valueJson
= new JSONObject();
149 valueJson
.put("type", "long");
150 valueJson
.put("value", keepAlpha ? color
: 0x00FFFFFF & color
);
151 json
.put("Color", valueJson
);
153 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:Color", json
.toString()));
154 changeFontColorBoxColor(color
);
156 } catch (JSONException e
) {
162 * 0x00FFFFFF & color operation removes the alpha which is FF,
163 * if we don't remove it, the color value becomes negative which is not recognized by LOK
165 private void sendFontBackColorChange(int color
, boolean keepAlpha
) {
167 JSONObject json
= new JSONObject();
168 JSONObject valueJson
= new JSONObject();
169 valueJson
.put("type", "long");
170 valueJson
.put("value", keepAlpha ? color
: 0x00FFFFFF & color
);
171 if(mActivity
.getTileProvider().isSpreadsheet()){
172 json
.put("BackgroundColor", valueJson
);
173 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:BackgroundColor", json
.toString()));
175 json
.put("CharBackColor", valueJson
);
176 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UNO_COMMAND
, ".uno:CharBackColor", json
.toString()));
179 changeFontBackColorBoxColor(color
);
181 } catch (JSONException e
) {
188 public void onItemSelected(AdapterView
<?
> parent
, View view
, int pos
, long id
) {
189 if (mFontList
.isEmpty() || !mFontNameSpinnerSet
)
191 if (parent
== mActivity
.findViewById(R
.id
.font_name_spinner
)) {
192 String currentFontSelected
= parent
.getItemAtPosition(pos
).toString();
193 if (!currentFontSelected
.equals(mCurrentFontSelected
)) {
194 mCurrentFontSelected
= currentFontSelected
;
195 sendFontChange(mCurrentFontSelected
);
197 } else if (parent
== mActivity
.findViewById(R
.id
.font_size_spinner
)) {
198 String currentFontSizeSelected
= parent
.getItemAtPosition(pos
).toString();
199 if (!currentFontSizeSelected
.equals(mCurrentFontSizeSelected
)) {
200 mCurrentFontSizeSelected
= currentFontSizeSelected
;
201 sendFontSizeChange(mCurrentFontSizeSelected
);
207 public void onNothingSelected(AdapterView parent
) {
211 public void parseJson(String json
) {
213 mAllFontSizes
.clear();
215 JSONObject jObject
= new JSONObject(json
);
216 JSONObject jObject2
= jObject
.getJSONObject("commandValues");
217 Iterator
<String
> keys
= jObject2
.keys();
218 ArrayList
<String
> fontSizes
;
219 while (keys
.hasNext()) {
220 String key
= keys
.next();
222 JSONArray array
= jObject2
.getJSONArray(key
);
223 fontSizes
= new ArrayList
<>();
224 for (int i
= 0; i
< array
.length(); i
++) {
225 fontSizes
.add(array
.getString(i
));
227 mAllFontSizes
.put(key
, fontSizes
);
229 } catch (JSONException e
) {
234 public void setupFontViews() {
235 LOKitShell
.getMainHandler().post(new Runnable() {
237 setupFontNameSpinner();
238 setupFontSizeSpinner();
240 setupBackColorPicker();
245 private void setupFontNameSpinner() {
246 Spinner fontSpinner
= mActivity
.findViewById(R
.id
.font_name_spinner
);
247 ArrayAdapter
<String
> dataAdapter
= new ArrayAdapter
<>(mActivity
, android
.R
.layout
.simple_spinner_item
, mFontList
);
248 dataAdapter
.setDropDownViewResource(android
.R
.layout
.simple_spinner_dropdown_item
);
249 fontSpinner
.setAdapter(dataAdapter
);
252 private void setupFontSizeSpinner() {
253 Spinner fontSizeSpinner
= mActivity
.findViewById(R
.id
.font_size_spinner
);
254 ArrayAdapter
<String
> dataAdapter
= new ArrayAdapter
<>(mActivity
, android
.R
.layout
.simple_spinner_item
, mFontSizes
);
255 dataAdapter
.setDropDownViewResource(android
.R
.layout
.simple_spinner_dropdown_item
);
256 fontSizeSpinner
.setAdapter(dataAdapter
);
259 private void setupColorPicker(){
260 LinearLayout colorPickerLayout
= mActivity
.findViewById(R
.id
.toolbar_color_picker
);
262 RecyclerView recyclerView
= colorPickerLayout
.findViewById(R
.id
.fontColorView
);
263 GridLayoutManager gridLayoutManager
= new GridLayoutManager(mActivity
, 11, GridLayoutManager
.VERTICAL
, true);
264 recyclerView
.setHasFixedSize(true);
265 recyclerView
.setLayoutManager(gridLayoutManager
);
269 RecyclerView recyclerView2
= colorPickerLayout
.findViewById(R
.id
.fontColorViewSub
);
270 GridLayoutManager gridLayoutManager2
= new GridLayoutManager(mActivity
,4);
271 recyclerView2
.setHasFixedSize(true);
272 recyclerView2
.addItemDecoration(new RecyclerView
.ItemDecoration() {
275 public void getItemOffsets(Rect outRect
, View view
, RecyclerView parent
, RecyclerView
.State state
) {
282 recyclerView2
.setLayoutManager(gridLayoutManager2
);
284 ColorPaletteAdapter colorPaletteAdapter
= new ColorPaletteAdapter(mActivity
, colorPaletteListener
);
285 recyclerView2
.setAdapter(colorPaletteAdapter
);
287 this.colorPickerAdapter
= new ColorPickerAdapter(mActivity
, colorPaletteAdapter
, colorPaletteListener
);
288 recyclerView
.setAdapter(colorPickerAdapter
);
289 RelativeLayout fontColorPicker
= mActivity
.findViewById(R
.id
.font_color_picker
);
290 ImageButton fontColorPickerButton
= mActivity
.findViewById(R
.id
.font_color_picker_button
);
291 View
.OnClickListener clickListener
= new View
.OnClickListener(){
293 public void onClick(View view
) {
294 toolBarBottomBehavior
.setState(BottomSheetBehavior
.STATE_COLLAPSED
);
295 colorPickerBehavior
.setState(BottomSheetBehavior
.STATE_EXPANDED
);
296 mActivity
.findViewById(R
.id
.search_toolbar
).setVisibility(View
.GONE
);
299 LinearLayout toolbarBottomLayout
= mActivity
.findViewById(R
.id
.toolbar_bottom
);
300 colorPickerBehavior
= BottomSheetBehavior
.from(colorPickerLayout
);
301 toolBarBottomBehavior
= BottomSheetBehavior
.from(toolbarBottomLayout
);
303 ImageButton pickerGoBackButton
= colorPickerLayout
.findViewById(R
.id
.button_go_back_color_picker
);
304 pickerGoBackButton
.setOnClickListener(new View
.OnClickListener() {
306 public void onClick(View view
) {
307 toolBarBottomBehavior
.setState(BottomSheetBehavior
.STATE_EXPANDED
);
308 colorPickerBehavior
.setState(BottomSheetBehavior
.STATE_COLLAPSED
);
313 fontColorPicker
.setOnClickListener(clickListener
);
314 fontColorPickerButton
.setOnClickListener(clickListener
);
316 final Button autoColorButton
= colorPickerLayout
.findViewById(R
.id
.button_auto_color
);
317 autoColorButton
.setOnClickListener(view
-> {
318 sendFontColorChange(COLOR_AUTO
, true);
322 private void setupBackColorPicker(){
323 LinearLayout backColorPickerLayout
= mActivity
.findViewById(R
.id
.toolbar_back_color_picker
);
325 RecyclerView recyclerView
= backColorPickerLayout
.findViewById(R
.id
.fontColorView
);
326 GridLayoutManager gridLayoutManager
= new GridLayoutManager(mActivity
, 11, GridLayoutManager
.VERTICAL
, true);
327 recyclerView
.setHasFixedSize(true);
328 recyclerView
.setLayoutManager(gridLayoutManager
);
332 RecyclerView recyclerView2
= backColorPickerLayout
.findViewById(R
.id
.fontColorViewSub
);
333 GridLayoutManager gridLayoutManager2
= new GridLayoutManager(mActivity
,4);
334 recyclerView2
.setHasFixedSize(true);
335 recyclerView2
.addItemDecoration(new RecyclerView
.ItemDecoration() {
338 public void getItemOffsets(Rect outRect
, View view
, RecyclerView parent
, RecyclerView
.State state
) {
345 recyclerView2
.setLayoutManager(gridLayoutManager2
);
347 ColorPaletteAdapter colorPaletteAdapter
= new ColorPaletteAdapter(mActivity
, backColorPaletteListener
);
348 recyclerView2
.setAdapter(colorPaletteAdapter
);
350 this.backColorPickerAdapter
= new ColorPickerAdapter(mActivity
, colorPaletteAdapter
, backColorPaletteListener
);
351 recyclerView
.setAdapter(backColorPickerAdapter
);
352 RelativeLayout fontColorPicker
= mActivity
.findViewById(R
.id
.font_back_color_picker
);
353 ImageButton fontColorPickerButton
= mActivity
.findViewById(R
.id
.font_back_color_picker_button
);
354 View
.OnClickListener clickListener
= new View
.OnClickListener(){
356 public void onClick(View view
) {
357 toolBarBottomBehavior
.setState(BottomSheetBehavior
.STATE_COLLAPSED
);
358 backColorPickerBehavior
.setState(BottomSheetBehavior
.STATE_EXPANDED
);
359 mActivity
.findViewById(R
.id
.search_toolbar
).setVisibility(View
.GONE
);
362 LinearLayout toolbarBottomLayout
= mActivity
.findViewById(R
.id
.toolbar_bottom
);
363 backColorPickerBehavior
= BottomSheetBehavior
.from(backColorPickerLayout
);
364 toolBarBottomBehavior
= BottomSheetBehavior
.from(toolbarBottomLayout
);
366 ImageButton pickerGoBackButton
= backColorPickerLayout
.findViewById(R
.id
.button_go_back_color_picker
);
367 pickerGoBackButton
.setOnClickListener(new View
.OnClickListener() {
369 public void onClick(View view
) {
370 toolBarBottomBehavior
.setState(BottomSheetBehavior
.STATE_EXPANDED
);
371 backColorPickerBehavior
.setState(BottomSheetBehavior
.STATE_COLLAPSED
);
376 fontColorPicker
.setOnClickListener(clickListener
);
377 fontColorPickerButton
.setOnClickListener(clickListener
);
379 final Button autoColorButton
= backColorPickerLayout
.findViewById(R
.id
.button_auto_color
);
380 autoColorButton
.setOnClickListener(view
-> {
381 sendFontBackColorChange(COLOR_AUTO
, true);
385 public void selectFont(final String fontName
) {
386 LOKitShell
.getMainHandler().post(new Runnable() {
388 selectFontCurrentThread(fontName
);
393 private void selectFontCurrentThread(String fontName
) {
394 Spinner spinner
= mActivity
.findViewById(R
.id
.font_name_spinner
);
395 if (!mFontNameSpinnerSet
) {
396 spinner
.setOnItemSelectedListener(this);
397 mFontNameSpinnerSet
= true;
400 if (fontName
.equals(mCurrentFontSelected
))
403 int position
= mFontList
.indexOf(fontName
);
404 if (position
!= -1) {
405 mCurrentFontSelected
= fontName
;
406 spinner
.setSelection(position
,false);
409 resetFontSizes(fontName
);
412 private void resetFontSizes(String fontName
) {
413 if (mAllFontSizes
.get(fontName
) != null) {
415 mFontSizes
.addAll(mAllFontSizes
.get(fontName
));
416 Spinner spinner
= mActivity
.findViewById(R
.id
.font_size_spinner
);
417 ArrayAdapter
<?
> arrayAdapter
= (ArrayAdapter
<?
>)spinner
.getAdapter();
418 arrayAdapter
.notifyDataSetChanged();
422 public void selectFontSize(final String fontSize
) {
423 LOKitShell
.getMainHandler().post(new Runnable() {
425 selectFontSizeCurrentThread(fontSize
);
430 private void selectFontSizeCurrentThread(String fontSize
) {
431 Spinner spinner
= mActivity
.findViewById(R
.id
.font_size_spinner
);
432 if (!mFontSizeSpinnerSet
) {
433 spinner
.setOnItemSelectedListener(this);
434 mFontSizeSpinnerSet
= true;
437 if (fontSize
.equals(mCurrentFontSizeSelected
))
440 int position
= mFontSizes
.indexOf(fontSize
);
441 if (position
!= -1) {
442 mCurrentFontSizeSelected
= fontSize
;
443 spinner
.setSelection(position
, false);