1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-19 00:19:25 +01:00

Add basic calendar chooser activity

This commit is contained in:
Arjan Schrijver 2024-01-15 17:48:04 +01:00
parent 75054b50a9
commit 8682234cbf
5 changed files with 239 additions and 4 deletions

View File

@ -848,6 +848,11 @@
android:name=".externalevents.opentracks.OpenTracksController"
android:label="OpenTracks controller and intent receiver"
android:exported="true"/>
<activity
android:name=".activities.dashboard.DashboardCalendarActivity"
android:label="@string/menuitem_calendar"
android:parentActivityName=".activities.MainActivity" />
</application>
</manifest>

View File

@ -25,7 +25,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -42,13 +41,13 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.AbstractDashboardWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardActiveTimeWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardCalendarActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardDistanceWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardGoalsWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardSleepWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardStepsWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardTodayWidget;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class DashboardFragment extends Fragment {
@ -107,8 +106,9 @@ public class DashboardFragment extends Fragment {
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.dashboard_show_calendar:
// TODO: implement calendar activity
GB.toast("The calendar view is not implemented yet", Toast.LENGTH_SHORT, GB.INFO);
Intent intent = new Intent(requireActivity(), DashboardCalendarActivity.class);
intent.putExtra(DashboardCalendarActivity.EXTRA_TIMESTAMP, day.getTimeInMillis());
startActivityForResult(intent, 0);
return false;
}
return super.onOptionsItemSelected(item);
@ -117,6 +117,12 @@ public class DashboardFragment extends Fragment {
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == DashboardCalendarActivity.RESULT_OK && data != null) {
long timeMillis = data.getLongExtra(DashboardCalendarActivity.EXTRA_TIMESTAMP, 0);
if (timeMillis != 0) {
day.setTimeInMillis(timeMillis);
}
}
gridLayout.removeAllViews();
todayWidget = null;
goalsWidget = null;

View File

@ -0,0 +1,164 @@
/* Copyright (C) 2023-2024 Arjan Schrijver
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 <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities.dashboard;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.widget.TextView;
import androidx.gridlayout.widget.GridLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
public class DashboardCalendarActivity extends AbstractGBActivity {
private static final Logger LOG = LoggerFactory.getLogger(DashboardCalendarActivity.class);
public static String EXTRA_TIMESTAMP = "dashboard_calendar_chosen_day";
TextView monthTextView;
TextView arrowLeft;
TextView arrowRight;
GridLayout calendarGrid;
Calendar cal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard_calendar);
monthTextView = findViewById(R.id.calendar_month);
calendarGrid = findViewById(R.id.dashboard_calendar_grid);
cal = Calendar.getInstance();
long receivedTimestamp = getIntent().getLongExtra(EXTRA_TIMESTAMP, 0);
if (receivedTimestamp != 0) cal.setTimeInMillis(receivedTimestamp);
arrowLeft = findViewById(R.id.arrow_left);
arrowLeft.setOnClickListener(v -> {
cal.add(Calendar.MONTH, -1);
draw();
});
arrowRight = findViewById(R.id.arrow_right);
arrowRight.setOnClickListener(v -> {
Calendar today = GregorianCalendar.getInstance();
if (!DateTimeUtils.isSameMonth(today, cal)) {
cal.add(Calendar.MONTH, 1);
draw();
}
});
draw();
}
private void draw() {
// Remove previous calendar days
calendarGrid.removeAllViews();
// Update month display
SimpleDateFormat monthFormat = new SimpleDateFormat("LLLL yyyy", Locale.getDefault());
monthTextView.setText(monthFormat.format(cal.getTime()));
Calendar today = GregorianCalendar.getInstance();
today.set(Calendar.HOUR, 23);
today.set(Calendar.MINUTE, 59);
today.set(Calendar.SECOND, 59);
if (DateTimeUtils.isSameMonth(today, cal)) {
arrowRight.setAlpha(0.5f);
} else {
arrowRight.setAlpha(1);
}
// Calculate grid cell size for dates
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int screenWidth = displayMetrics.widthPixels;
int cellSize = screenWidth / 7;
// Determine first day that should be displayed
Calendar drawCal = (Calendar) cal.clone();
drawCal.set(Calendar.DAY_OF_MONTH, 1);
int displayMonth = drawCal.get(Calendar.MONTH);
int firstDayOfWeek = cal.getFirstDayOfWeek();
int daysToFirstDay = (drawCal.get(Calendar.DAY_OF_WEEK) - firstDayOfWeek + 7) % 7;
drawCal.add(Calendar.DAY_OF_MONTH, -daysToFirstDay);
// Determine last day that should be displayed
Calendar lastDay = (Calendar) cal.clone();
lastDay.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
lastDay.add(Calendar.DAY_OF_MONTH, (firstDayOfWeek + 7 - lastDay.get(Calendar.DAY_OF_WEEK)) % 7);
// Add day names header
SimpleDateFormat dayFormat = new SimpleDateFormat("E", Locale.getDefault());
Calendar weekdays = Calendar.getInstance();
for (int i=0; i<7; i++) {
int currentDayOfWeek = (firstDayOfWeek + i - 1) % 7 + 1;
weekdays.set(Calendar.DAY_OF_WEEK, currentDayOfWeek);
createWeekdayCell(dayFormat.format(weekdays.getTime()), cellSize);
}
// Loop through month days and create grid cells for them
while (!DateTimeUtils.isSameDay(drawCal, lastDay)) {
boolean clickable = drawCal.get(Calendar.MONTH) == displayMonth;
if (drawCal.after(today)) clickable = false;
createDateCell(drawCal, cellSize, clickable);
drawCal.add(Calendar.DAY_OF_MONTH, 1);
}
}
private TextView prepareGridElement(int cellSize) {
GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams(
GridLayout.spec(GridLayout.UNDEFINED, GridLayout.FILL,1f),
GridLayout.spec(GridLayout.UNDEFINED, 1, GridLayout.FILL,1f)
);
int margin = cellSize / 10;
layoutParams.width = 0;
layoutParams.height = cellSize - 2 * margin;
layoutParams.setMargins(margin, margin, margin, margin);
TextView text = new TextView(this);
text.setLayoutParams(layoutParams);
text.setGravity(Gravity.CENTER);
return text;
}
private void createWeekdayCell(String day, int cellSize) {
TextView text = prepareGridElement(cellSize);
text.setText(day);
calendarGrid.addView(text);
}
private void createDateCell(Calendar day, int cellSize, boolean clickable) {
final long timestamp = day.getTimeInMillis();
TextView text = prepareGridElement(cellSize);
text.setText(String.valueOf(day.get(Calendar.DAY_OF_MONTH)));
if (clickable) {
GradientDrawable backgroundDrawable = new GradientDrawable();
backgroundDrawable.setShape(GradientDrawable.OVAL);
backgroundDrawable.setColor(Color.argb(50, 128, 128, 128));
text.setBackground(backgroundDrawable);
text.setOnClickListener(v -> {
Intent resultIntent = new Intent();
resultIntent.putExtra(EXTRA_TIMESTAMP, timestamp);
setResult(RESULT_OK, resultIntent);
finish();
});
}
calendarGrid.addView(text);
}
}

View File

@ -236,4 +236,16 @@ public class DateTimeUtils {
&& calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH)
&& calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH);
}
/**
* Determine whether two Calendar instances are in the same month
*
* @param calendar1 The first calendar to compare
* @param calendar2 The second calendar to compare
* @return true if the Calendar instances are in the same month
*/
public static boolean isSameMonth(Calendar calendar1, Calendar calendar2) {
return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)
&& calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH);
}
}

View File

@ -0,0 +1,48 @@
<android.widget.LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activities.dashboard.DashboardCalendarActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/calendar_month"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/calendar_month"
android:textStyle="bold"
android:textSize="30sp" />
<TextView
android:id="@+id/arrow_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="\u003C"
android:textStyle="bold"
android:textSize="40sp"
android:paddingHorizontal="8dp"
android:layout_toLeftOf="@+id/arrow_right" />
<TextView
android:id="@+id/arrow_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="\u003E"
android:textStyle="bold"
android:textSize="40sp"
android:paddingHorizontal="8dp"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
<androidx.gridlayout.widget.GridLayout
android:id="@+id/dashboard_calendar_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
app:columnCount="7" />
</android.widget.LinearLayout>