/* Copyright (C) 2023-2024 José Rebelo This file is part of Gadgetbridge. Gadgetbridge is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gadgetbridge is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.activities.widgets; import android.app.Activity; import android.os.Bundle; import android.view.MenuItem; import android.view.View; import android.widget.ArrayAdapter; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity; import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetLayout; import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetManager; import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetPart; import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetPartSubtype; import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetScreen; import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetType; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.GB; public class WidgetScreenDetailsActivity extends AbstractGBActivity { private static final Logger LOG = LoggerFactory.getLogger(WidgetScreenDetailsActivity.class); private WidgetScreen widgetScreen; private WidgetManager widgetManager; private View cardWidgetTopLeft; private View cardWidgetTopRight; private View cardWidgetCenter; private View cardWidgetBotLeft; private View cardWidgetBotRight; private TextView labelWidgetScreenLayout; private TextView labelWidgetTopLeft; private TextView labelWidgetTopRight; private TextView labelWidgetCenter; private TextView labelWidgetBotLeft; private TextView labelWidgetBotRight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_widget_screen_details); final GBDevice device = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE); if (device == null) { LOG.error("device must not be null"); finish(); return; } widgetScreen = (WidgetScreen) getIntent().getSerializableExtra(WidgetScreen.EXTRA_WIDGET_SCREEN); if (widgetScreen == null) { GB.toast("No widget screen provided to WidgetScreenDetailsActivity", Toast.LENGTH_LONG, GB.ERROR); finish(); return; } widgetManager = device.getDeviceCoordinator().getWidgetManager(device); // Save button final FloatingActionButton fab = findViewById(R.id.fab_save); fab.setOnClickListener(view -> { for (final WidgetPart part : widgetScreen.getParts()) { if (part.getId() == null) { GB.toast(getBaseContext().getString(R.string.widget_missing_parts), Toast.LENGTH_LONG, GB.WARN); return; } } updateWidgetScreen(); WidgetScreenDetailsActivity.this.setResult(Activity.RESULT_OK); finish(); }); // Layouts final List supportedLayouts = widgetManager.getSupportedWidgetLayouts(); final String[] layoutStrings = new String[supportedLayouts.size()]; for (int i = 0; i < supportedLayouts.size(); i++) { layoutStrings[i] = getBaseContext().getString(supportedLayouts.get(i).getName()); } final ArrayAdapter layoutAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, layoutStrings); final View cardLayout = findViewById(R.id.card_layout); cardLayout.setOnClickListener(view -> { new MaterialAlertDialogBuilder(WidgetScreenDetailsActivity.this).setAdapter(layoutAdapter, (dialogInterface, i) -> { if (widgetScreen.getLayout() != supportedLayouts.get(i)) { final ArrayList defaultParts = new ArrayList<>(); for (final WidgetType widgetType : supportedLayouts.get(i).getWidgetTypes()) { defaultParts.add(new WidgetPart(null, "", widgetType)); } widgetScreen.setParts(defaultParts); } widgetScreen.setLayout(supportedLayouts.get(i)); updateUiFromWidget(); }).setTitle(R.string.widget_layout).create().show(); }); cardWidgetTopLeft = findViewById(R.id.card_widget_top_left); cardWidgetTopRight = findViewById(R.id.card_widget_top_right); cardWidgetCenter = findViewById(R.id.card_widget_center); cardWidgetBotLeft = findViewById(R.id.card_widget_bottom_left); cardWidgetBotRight = findViewById(R.id.card_widget_bottom_right); labelWidgetScreenLayout = findViewById(R.id.widget_screen_layout); labelWidgetTopLeft = findViewById(R.id.widget_top_left); labelWidgetTopRight = findViewById(R.id.widget_top_right); labelWidgetCenter = findViewById(R.id.widget_center); labelWidgetBotLeft = findViewById(R.id.widget_bottom_left); labelWidgetBotRight = findViewById(R.id.widget_bottom_right); updateUiFromWidget(); } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case android.R.id.home: // back button // TODO confirm when exiting without saving finish(); return true; } return super.onOptionsItemSelected(item); } private void updateWidgetScreen() { widgetManager.saveScreen(widgetScreen); } @Override protected void onSaveInstanceState(@NonNull final Bundle state) { super.onSaveInstanceState(state); state.putSerializable("widgetScreen", widgetScreen); } @Override protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); widgetScreen = (WidgetScreen) savedInstanceState.getSerializable("widgetScreen"); updateUiFromWidget(); } private void updateUiFromWidget() { labelWidgetScreenLayout.setText(widgetScreen.getLayout().getName()); switch (widgetScreen.getLayout()) { case TOP_1_BOT_2: updateWidget(cardWidgetTopLeft, labelWidgetTopLeft, -1); updateWidget(cardWidgetTopRight, labelWidgetTopRight, -1); updateWidget(cardWidgetCenter, labelWidgetCenter, 0); updateWidget(cardWidgetBotLeft, labelWidgetBotLeft, 1); updateWidget(cardWidgetBotRight, labelWidgetBotRight, 2); break; case TOP_2_BOT_1: updateWidget(cardWidgetTopLeft, labelWidgetTopLeft, 0); updateWidget(cardWidgetTopRight, labelWidgetTopRight, 1); updateWidget(cardWidgetCenter, labelWidgetCenter, 2); updateWidget(cardWidgetBotLeft, labelWidgetBotLeft, -1); updateWidget(cardWidgetBotRight, labelWidgetBotRight, -1); break; case TOP_2_BOT_2: updateWidget(cardWidgetTopLeft, labelWidgetTopLeft, 0); updateWidget(cardWidgetTopRight, labelWidgetTopRight, 1); updateWidget(cardWidgetCenter, labelWidgetCenter, -1); updateWidget(cardWidgetBotLeft, labelWidgetBotLeft, 2); updateWidget(cardWidgetBotRight, labelWidgetBotRight, 3); break; case ONE_BY_TWO_SINGLE: case TWO_BY_TWO_SINGLE: updateWidget(cardWidgetTopLeft, labelWidgetTopLeft, -1); updateWidget(cardWidgetTopRight, labelWidgetTopRight, -1); updateWidget(cardWidgetCenter, labelWidgetCenter, 0); updateWidget(cardWidgetBotLeft, labelWidgetBotLeft, -1); updateWidget(cardWidgetBotRight, labelWidgetBotRight, -1); break; case TWO: updateWidget(cardWidgetTopLeft, labelWidgetTopLeft, -1); updateWidget(cardWidgetTopRight, labelWidgetTopRight, 0); updateWidget(cardWidgetCenter, labelWidgetCenter, 1); updateWidget(cardWidgetBotLeft, labelWidgetBotLeft, -1); updateWidget(cardWidgetBotRight, labelWidgetBotRight, -1); break; default: throw new IllegalStateException("Unknown layout " + widgetScreen.getLayout()); } } private void updateWidget(final View card, final TextView label, final int partIdx) { final boolean validPart = partIdx >= 0 && partIdx < widgetScreen.getParts().size(); card.setVisibility(validPart ? View.VISIBLE : View.GONE); if (!validPart) { card.setOnClickListener(null); label.setText(R.string.not_set); return; } final WidgetPart widgetPart = widgetScreen.getParts().get(partIdx); if (widgetPart.getId() == null) { label.setText(R.string.not_set); } else { label.setText(widgetPart.getFullName()); } // Select widget part final List supportedParts = widgetManager.getSupportedWidgetParts(widgetPart.getType()); final String[] layoutStrings = new String[supportedParts.size()]; for (int i = 0; i < supportedParts.size(); i++) { layoutStrings[i] = supportedParts.get(i).getName(); } final ArrayAdapter partAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, layoutStrings); card.setOnClickListener(view -> { new MaterialAlertDialogBuilder(WidgetScreenDetailsActivity.this).setAdapter(partAdapter, (dialogInterface, i) -> { final WidgetPart selectedPart = supportedParts.get(i); final List supportedSubtypes = selectedPart.getSupportedSubtypes(); if (supportedSubtypes.isEmpty()) { // No subtypes selected widgetScreen.getParts().set(partIdx, selectedPart); updateUiFromWidget(); return; } // If the selected part supports subtypes, the user must select a subtype final String[] subtypeStrings = new String[supportedSubtypes.size()]; for (int j = 0; j < supportedSubtypes.size(); j++) { subtypeStrings[j] = supportedSubtypes.get(j).getName(); } final ArrayAdapter subtypesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, subtypeStrings); new MaterialAlertDialogBuilder(WidgetScreenDetailsActivity.this).setAdapter(subtypesAdapter, (dialogInterface1, j) -> { final WidgetPartSubtype selectedSubtype = supportedSubtypes.get(j); selectedPart.setSubtype(selectedSubtype); widgetScreen.getParts().set(partIdx, selectedPart); updateUiFromWidget(); }).setTitle(R.string.widget_subtype).create().show(); }).setTitle(R.string.widget).create().show(); }); } }